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.extapi.psi.PsiFileBase; 020 import com.intellij.lang.ASTNode; 021 import com.intellij.lang.FileASTNode; 022 import com.intellij.openapi.components.ServiceManager; 023 import com.intellij.openapi.fileTypes.FileType; 024 import com.intellij.psi.*; 025 import com.intellij.psi.stubs.StubElement; 026 import com.intellij.psi.util.PsiTreeUtil; 027 import kotlin.collections.ArraysKt; 028 import kotlin.jvm.functions.Function1; 029 import org.jetbrains.annotations.NotNull; 030 import org.jetbrains.annotations.Nullable; 031 import org.jetbrains.kotlin.KtNodeTypes; 032 import org.jetbrains.kotlin.idea.KotlinFileType; 033 import org.jetbrains.kotlin.idea.KotlinLanguage; 034 import org.jetbrains.kotlin.name.FqName; 035 import org.jetbrains.kotlin.psi.stubs.KotlinFileStub; 036 import org.jetbrains.kotlin.psi.stubs.elements.KtPlaceHolderStubElementType; 037 import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes; 038 039 import java.util.Arrays; 040 import java.util.Collections; 041 import java.util.List; 042 043 public class KtFile extends PsiFileBase implements KtDeclarationContainer, KtAnnotated, KtElement, PsiClassOwner, PsiNamedElement { 044 045 private final boolean isCompiled; 046 047 public KtFile(FileViewProvider viewProvider, boolean compiled) { 048 super(viewProvider, KotlinLanguage.INSTANCE); 049 this.isCompiled = compiled; 050 } 051 052 @Override 053 public FileASTNode getNode() { 054 return super.getNode(); 055 } 056 057 public boolean isCompiled() { 058 return isCompiled; 059 } 060 061 @Override 062 @NotNull 063 public FileType getFileType() { 064 return KotlinFileType.INSTANCE; 065 } 066 067 @Override 068 public String toString() { 069 return "JetFile: " + getName(); 070 } 071 072 @NotNull 073 @Override 074 public List<KtDeclaration> getDeclarations() { 075 KotlinFileStub stub = getStub(); 076 if (stub != null) { 077 return Arrays.asList(stub.getChildrenByType(KtStubElementTypes.DECLARATION_TYPES, KtDeclaration.ARRAY_FACTORY)); 078 } 079 return PsiTreeUtil.getChildrenOfTypeAsList(this, KtDeclaration.class); 080 } 081 082 @Nullable 083 public KtImportList getImportList() { 084 return findChildByTypeOrClass(KtStubElementTypes.IMPORT_LIST, KtImportList.class); 085 } 086 087 @Nullable 088 public KtFileAnnotationList getFileAnnotationList() { 089 return findChildByTypeOrClass(KtStubElementTypes.FILE_ANNOTATION_LIST, KtFileAnnotationList.class); 090 } 091 092 @Nullable 093 public <T extends KtElementImplStub<? extends StubElement<?>>> T findChildByTypeOrClass( 094 @NotNull KtPlaceHolderStubElementType<T> elementType, 095 @NotNull Class<T> elementClass 096 ) { 097 KotlinFileStub stub = getStub(); 098 if (stub != null) { 099 StubElement<T> importListStub = stub.findChildStubByType(elementType); 100 return importListStub != null ? importListStub.getPsi() : null; 101 } 102 return findChildByClass(elementClass); 103 } 104 105 @NotNull 106 public List<KtImportDirective> getImportDirectives() { 107 KtImportList importList = getImportList(); 108 return importList != null ? importList.getImports() : Collections.<KtImportDirective>emptyList(); 109 } 110 111 @Nullable 112 public KtImportDirective findImportByAlias(@NotNull String name) { 113 for (KtImportDirective directive : getImportDirectives()) { 114 if (name.equals(directive.getAliasName())) { 115 return directive; 116 } 117 } 118 return null; 119 } 120 121 // scripts have no package directive, all other files must have package directives 122 @Nullable 123 public KtPackageDirective getPackageDirective() { 124 KotlinFileStub stub = getStub(); 125 if (stub != null) { 126 StubElement<KtPackageDirective> packageDirectiveStub = stub.findChildStubByType(KtStubElementTypes.PACKAGE_DIRECTIVE); 127 return packageDirectiveStub != null ? packageDirectiveStub.getPsi() : null; 128 } 129 ASTNode ast = getNode().findChildByType(KtNodeTypes.PACKAGE_DIRECTIVE); 130 return ast != null ? (KtPackageDirective) ast.getPsi() : null; 131 } 132 133 @Deprecated // getPackageFqName should be used instead 134 @Override 135 @NotNull 136 public String getPackageName() { 137 return getPackageFqName().asString(); 138 } 139 140 @NotNull 141 public FqName getPackageFqName() { 142 KotlinFileStub stub = getStub(); 143 if (stub != null) { 144 return stub.getPackageFqName(); 145 } 146 return getPackageFqNameByTree(); 147 } 148 149 @NotNull 150 public FqName getPackageFqNameByTree() { 151 KtPackageDirective packageDirective = getPackageDirective(); 152 if (packageDirective == null) { 153 return FqName.ROOT; 154 } 155 return packageDirective.getFqName(); 156 } 157 158 @Override 159 @Nullable 160 public KotlinFileStub getStub() { 161 return (KotlinFileStub) super.getStub(); 162 } 163 164 @NotNull 165 @Override 166 public PsiClass[] getClasses() { 167 KtFileClassProvider fileClassProvider = ServiceManager.getService(getProject(), KtFileClassProvider.class); 168 // TODO We don't currently support finding light classes for scripts 169 if (fileClassProvider != null && !isScript()) { 170 return fileClassProvider.getFileClasses(this); 171 } 172 return PsiClass.EMPTY_ARRAY; 173 } 174 175 @Override 176 public void setPackageName(String packageName) { } 177 178 @Nullable 179 public KtScript getScript() { 180 return PsiTreeUtil.getChildOfType(this, KtScript.class); 181 } 182 183 public boolean isScript() { 184 KotlinFileStub stub = getStub(); 185 if (stub != null) { 186 return stub.isScript(); 187 } 188 return isScriptByTree(); 189 } 190 191 public boolean isScriptByTree() { 192 return getScript() != null; 193 } 194 195 @NotNull 196 @Override 197 public String getName() { 198 return super.getName(); // TODO 199 } 200 201 @Override 202 public void accept(@NotNull PsiElementVisitor visitor) { 203 if (visitor instanceof KtVisitor) { 204 accept((KtVisitor) visitor, null); 205 } 206 else { 207 visitor.visitFile(this); 208 } 209 } 210 211 @NotNull 212 @Override 213 public KtFile getContainingKtFile() { 214 return this; 215 } 216 217 @Override 218 public <D> void acceptChildren(@NotNull KtVisitor<Void, D> visitor, D data) { 219 KtPsiUtil.visitChildren(this, visitor, data); 220 } 221 222 @Override 223 public <R, D> R accept(@NotNull KtVisitor<R, D> visitor, D data) { 224 return visitor.visitKtFile(this, data); 225 } 226 227 @NotNull 228 @Override 229 public List<KtAnnotation> getAnnotations() { 230 KtFileAnnotationList fileAnnotationList = getFileAnnotationList(); 231 if (fileAnnotationList == null) return Collections.emptyList(); 232 233 return fileAnnotationList.getAnnotations(); 234 } 235 236 @NotNull 237 @Override 238 public List<KtAnnotationEntry> getAnnotationEntries() { 239 KtFileAnnotationList fileAnnotationList = getFileAnnotationList(); 240 if (fileAnnotationList == null) return Collections.emptyList(); 241 242 return fileAnnotationList.getAnnotationEntries(); 243 } 244 245 /** 246 * @return annotations that do not belong to any declaration due to incomplete code or syntax errors 247 */ 248 @NotNull 249 public List<KtAnnotationEntry> getDanglingAnnotations() { 250 KotlinFileStub stub = getStub(); 251 KtModifierList[] danglingModifierLists = stub == null 252 ? findChildrenByClass(KtModifierList.class) 253 : stub.getChildrenByType( 254 KtStubElementTypes.MODIFIER_LIST, 255 KtStubElementTypes.MODIFIER_LIST.getArrayFactory() 256 ); 257 return ArraysKt.flatMap( 258 danglingModifierLists, 259 new Function1<KtModifierList, Iterable<KtAnnotationEntry>>() { 260 @Override 261 public Iterable<KtAnnotationEntry> invoke(KtModifierList modifierList) { 262 return modifierList.getAnnotationEntries(); 263 } 264 }); 265 } 266 }