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