Rename module jet.as.java.psi -> light-classes

This commit is contained in:
Alexander Udalov
2015-01-03 12:38:41 +03:00
parent be95a4fee7
commit b1809f8d40
43 changed files with 11 additions and 12 deletions
+17
View File
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="backend" />
<orderEntry type="module" module-name="frontend" />
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="library" scope="PROVIDED" name="intellij-core" level="project" />
<orderEntry type="module" module-name="util" />
</component>
</module>
@@ -0,0 +1,152 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.UserDataHolder;
import com.intellij.psi.*;
import com.intellij.psi.impl.compiled.ClsClassImpl;
import com.intellij.psi.impl.compiled.ClsEnumConstantImpl;
import com.intellij.psi.impl.compiled.ClsFieldImpl;
import com.intellij.psi.impl.compiled.ClsRepositoryPsiElement;
import com.intellij.psi.impl.java.stubs.*;
import com.intellij.psi.stubs.StubBase;
import com.intellij.psi.stubs.StubElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetDeclaration;
class ClsWrapperStubPsiFactory extends StubPsiFactory {
public static final Key<PsiElement> ORIGIN_ELEMENT = Key.create("ORIGIN_ELEMENT");
private final StubPsiFactory delegate = new ClsStubPsiFactory();
public static JetDeclaration getOriginalDeclaration(PsiMember member) {
if (member instanceof ClsRepositoryPsiElement<?>) {
StubElement stubElement = ((ClsRepositoryPsiElement<?>) member).getStub();
if (stubElement instanceof UserDataHolder) {
PsiElement original = ((UserDataHolder) stubElement).getUserData(ORIGIN_ELEMENT);
if (original instanceof JetDeclaration) {
return (JetDeclaration) original;
}
}
}
return null;
}
@Override
public PsiClass createClass(PsiClassStub stub) {
final PsiElement origin = ((StubBase) stub).getUserData(ORIGIN_ELEMENT);
if (origin == null) return delegate.createClass(stub);
return new ClsClassImpl(stub) {
@NotNull
@Override
public PsiElement getNavigationElement() {
return origin;
}
};
}
@Override
public PsiAnnotation createAnnotation(PsiAnnotationStub stub) {
return delegate.createAnnotation(stub);
}
@Override
public PsiClassInitializer createClassInitializer(PsiClassInitializerStub stub) {
return delegate.createClassInitializer(stub);
}
@Override
public PsiReferenceList createClassReferenceList(PsiClassReferenceListStub stub) {
return delegate.createClassReferenceList(stub);
}
@Override
public PsiField createField(PsiFieldStub stub) {
final PsiElement origin = ((StubBase) stub).getUserData(ORIGIN_ELEMENT);
if (origin == null) return delegate.createField(stub);
if (stub.isEnumConstant()) {
return new ClsEnumConstantImpl(stub) {
@NotNull
@Override
public PsiElement getNavigationElement() {
return origin;
}
};
}
else {
return new ClsFieldImpl(stub) {
@NotNull
@Override
public PsiElement getNavigationElement() {
return origin;
}
};
}
}
@Override
public PsiImportList createImportList(PsiImportListStub stub) {
return delegate.createImportList(stub);
}
@Override
public PsiImportStatementBase createImportStatement(PsiImportStatementStub stub) {
return delegate.createImportStatement(stub);
}
@Override
public PsiMethod createMethod(PsiMethodStub stub) {
return delegate.createMethod(stub);
}
@Override
public PsiModifierList createModifierList(PsiModifierListStub stub) {
return delegate.createModifierList(stub);
}
@Override
public PsiParameter createParameter(PsiParameterStub stub) {
return delegate.createParameter(stub);
}
@Override
public PsiParameterList createParameterList(PsiParameterListStub stub) {
return delegate.createParameterList(stub);
}
@Override
public PsiTypeParameter createTypeParameter(PsiTypeParameterStub stub) {
return delegate.createTypeParameter(stub);
}
@Override
public PsiTypeParameterList createTypeParameterList(PsiTypeParameterListStub stub) {
return delegate.createTypeParameterList(stub);
}
@Override
public PsiAnnotationParameterList createAnnotationParameterList(PsiAnnotationParameterListStub stub) {
return delegate.createAnnotationParameterList(stub);
}
@Override
public PsiNameValuePair createNameValuePair(PsiNameValuePairStub stub) {
return delegate.createNameValuePair(stub);
}
}
@@ -0,0 +1,99 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.light.AbstractLightClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.plugin.JetLanguage;
/**
* This class serves as a workaround for usages of {@link JavaElementFinder#findClasses} which eventually only need names of files
* containing the class. When queried for a package class (e.g. test/TestPackage), {@code findClasses} along with a
* {@link KotlinLightClassForPackage} would also return multiple instances of this class for each file present in the package. The client
* code can make use of every file in the package then, since {@code getContainingFile} of these instances will represent the whole package.
* <p/>
* See {@link LineBreakpoint#findClassCandidatesInSourceContent} for the primary usage this was introduced
*/
public class FakeLightClassForFileOfPackage extends AbstractLightClass implements KotlinLightClass, JetJavaMirrorMarker {
private final KotlinLightClassForPackage delegate;
private final JetFile file;
public FakeLightClassForFileOfPackage(
@NotNull PsiManager manager, @NotNull KotlinLightClassForPackage delegate, @NotNull JetFile file
) {
super(manager);
this.delegate = delegate;
this.file = file;
}
@Nullable
@Override
public JetClassOrObject getOrigin() {
return null;
}
@Override
public PsiFile getContainingFile() {
return file;
}
@Override
public boolean isValid() {
// This is intentionally false to prevent using this as a real class
return false;
}
@NotNull
@Override
public FqName getFqName() {
return delegate.getFqName();
}
@NotNull
@Override
public PsiClass getDelegate() {
return delegate;
}
@NotNull
@Override
public PsiElement copy() {
return new FakeLightClassForFileOfPackage(getManager(), delegate, file);
}
@Override
public String getText() {
return null;
}
@NotNull
@Override
public Language getLanguage() {
return JetLanguage.INSTANCE;
}
}
@@ -0,0 +1,268 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Sets;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Condition;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.SmartList;
import com.intellij.util.containers.SLRUCache;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetEnumEntry;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.KotlinFinderMarker;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.NamePackage;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class JavaElementFinder extends PsiElementFinder implements KotlinFinderMarker {
@NotNull
public static JavaElementFinder getInstance(@NotNull Project project) {
PsiElementFinder[] extensions = Extensions.getArea(project).getExtensionPoint(PsiElementFinder.EP_NAME).getExtensions();
for (PsiElementFinder extension : extensions) {
if (extension instanceof JavaElementFinder) {
return (JavaElementFinder) extension;
}
}
throw new IllegalStateException(JavaElementFinder.class.getSimpleName() + " is not found for project " + project);
}
private final Project project;
private final PsiManager psiManager;
private final LightClassGenerationSupport lightClassGenerationSupport;
private final CachedValue<SLRUCache<FindClassesRequest, PsiClass[]>> findClassesCache;
public JavaElementFinder(
@NotNull Project project,
@NotNull LightClassGenerationSupport lightClassGenerationSupport
) {
this.project = project;
this.psiManager = PsiManager.getInstance(project);
this.lightClassGenerationSupport = lightClassGenerationSupport;
this.findClassesCache = CachedValuesManager.getManager(project).createCachedValue(
new CachedValueProvider<SLRUCache<FindClassesRequest, PsiClass[]>>() {
@Nullable
@Override
public Result<SLRUCache<FindClassesRequest, PsiClass[]>> compute() {
return new Result<SLRUCache<FindClassesRequest, PsiClass[]>>(
new SLRUCache<FindClassesRequest, PsiClass[]>(30, 10) {
@NotNull
@Override
public PsiClass[] createValue(FindClassesRequest key) {
return doFindClasses(key.fqName, key.scope);
}
},
PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
);
}
},
false
);
}
@Override
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
PsiClass[] allClasses = findClasses(qualifiedName, scope);
return allClasses.length > 0 ? allClasses[0] : null;
}
@NotNull
@Override
public PsiClass[] findClasses(@NotNull String qualifiedNameString, @NotNull GlobalSearchScope scope) {
SLRUCache<FindClassesRequest, PsiClass[]> value = findClassesCache.getValue();
synchronized (value) {
return value.get(new FindClassesRequest(qualifiedNameString, scope));
}
}
private PsiClass[] doFindClasses(String qualifiedNameString, GlobalSearchScope scope) {
if (!NamePackage.isValidJavaFqName(qualifiedNameString)) {
return PsiClass.EMPTY_ARRAY;
}
List<PsiClass> answer = new SmartList<PsiClass>();
FqName qualifiedName = new FqName(qualifiedNameString);
findClassesAndObjects(qualifiedName, scope, answer);
if (PackageClassUtils.isPackageClassFqName(qualifiedName)) {
answer.addAll(lightClassGenerationSupport.getPackageClasses(qualifiedName.parent(), scope));
}
return answer.toArray(new PsiClass[answer.size()]);
}
// Finds explicitly declared classes and objects, not package classes
private void findClassesAndObjects(FqName qualifiedName, GlobalSearchScope scope, List<PsiClass> answer) {
Collection<JetClassOrObject> classOrObjectDeclarations =
lightClassGenerationSupport.findClassOrObjectDeclarations(qualifiedName, scope);
for (JetClassOrObject declaration : classOrObjectDeclarations) {
if (!(declaration instanceof JetEnumEntry)) {
PsiClass lightClass = LightClassUtil.getPsiClass(declaration);
if (lightClass != null) {
answer.add(lightClass);
}
}
}
}
@NotNull
@Override
public Set<String> getClassNames(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
Collection<JetClassOrObject> declarations = lightClassGenerationSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope);
Set<String> answer = Sets.newHashSet();
answer.add(PackageClassUtils.getPackageClassName(packageFQN));
for (JetClassOrObject declaration : declarations) {
String name = declaration.getName();
if (name != null) {
answer.add(name);
}
}
return answer;
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedNameString) {
if (!NamePackage.isValidJavaFqName(qualifiedNameString)) {
return null;
}
FqName fqName = new FqName(qualifiedNameString);
// allScope() because the contract says that the whole project
GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
if (lightClassGenerationSupport.packageExists(fqName, allScope)) {
return new JetLightPackage(psiManager, fqName, allScope);
}
return null;
}
@NotNull
@Override
public PsiPackage[] getSubPackages(@NotNull PsiPackage psiPackage, @NotNull final GlobalSearchScope scope) {
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
Collection<FqName> subpackages = lightClassGenerationSupport.getSubPackages(packageFQN, scope);
Collection<PsiPackage> answer = Collections2.transform(subpackages, new Function<FqName, PsiPackage>() {
@Override
public PsiPackage apply(@Nullable FqName input) {
return new JetLightPackage(psiManager, input, scope);
}
});
return answer.toArray(new PsiPackage[answer.size()]);
}
@NotNull
@Override
public PsiClass[] getClasses(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
List<PsiClass> answer = new SmartList<PsiClass>();
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
answer.addAll(lightClassGenerationSupport.getPackageClasses(packageFQN, scope));
Collection<JetClassOrObject> declarations = lightClassGenerationSupport.findClassOrObjectDeclarationsInPackage(packageFQN, scope);
for (JetClassOrObject declaration : declarations) {
PsiClass aClass = LightClassUtil.getPsiClass(declaration);
if (aClass != null) {
answer.add(aClass);
}
}
return answer.toArray(new PsiClass[answer.size()]);
}
// implements a method added in 14.1
@NotNull
public PsiFile[] getPackageFiles(@NotNull PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
FqName packageFQN = new FqName(psiPackage.getQualifiedName());
Collection<JetFile> result = lightClassGenerationSupport.findFilesForPackage(packageFQN, scope);
return result.toArray(new PsiFile[result.size()]);
}
// implements a method added in IDEA 14.1
@SuppressWarnings({"UnusedDeclaration", "MethodMayBeStatic"})
@Nullable
public Condition<PsiFile> getPackageFilesFilter(@NotNull final PsiPackage psiPackage, @NotNull GlobalSearchScope scope) {
return new Condition<PsiFile>() {
@Override
public boolean value(@Nullable PsiFile input) {
if (!(input instanceof JetFile)) {
return true;
}
return psiPackage.getQualifiedName().equals(((JetFile) input).getPackageFqName().asString());
}
};
}
private static class FindClassesRequest {
private final String fqName;
private final GlobalSearchScope scope;
private FindClassesRequest(@NotNull String fqName, @NotNull GlobalSearchScope scope) {
this.fqName = fqName;
this.scope = scope;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FindClassesRequest request = (FindClassesRequest) o;
if (!fqName.equals(request.fqName)) return false;
if (!scope.equals(request.scope)) return false;
return true;
}
@Override
public int hashCode() {
int result = fqName.hashCode();
result = 31 * result + (scope.hashCode());
return result;
}
}
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.file.PsiPackageImpl;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.name.FqName;
public class JetLightPackage extends PsiPackageImpl {
private final FqName fqName;
private final GlobalSearchScope scope;
public JetLightPackage(PsiManager manager, FqName qualifiedName, GlobalSearchScope scope) {
super(manager, qualifiedName.asString());
this.fqName = qualifiedName;
this.scope = scope;
}
@NotNull
@Override
public PsiElement copy() {
return new JetLightPackage(getManager(), fqName, scope);
}
@Override
public boolean isValid() {
return LightClassGenerationSupport.getInstance(getProject()).packageExists(fqName, scope);
}
}
@@ -0,0 +1,142 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.*
import com.intellij.psi.impl.PsiModificationTrackerImpl
import com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.*
import com.intellij.psi.impl.PsiTreeChangeEventImpl
import com.intellij.psi.impl.PsiTreeChangePreprocessor
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.jet.lang.psi.*
import com.intellij.psi.util.PsiTreeUtil
/**
* Tested in OutOfBlockModificationTestGenerated
*/
public class KotlinCodeBlockModificationListener(modificationTracker: PsiModificationTracker) : PsiTreeChangePreprocessor {
private val myModificationTracker = modificationTracker as PsiModificationTrackerImpl
override fun treeChanged(event: PsiTreeChangeEventImpl) {
if (event.getFile() !is JetFile) return
when (event.getCode()) {
BEFORE_CHILDREN_CHANGE,
BEFORE_PROPERTY_CHANGE,
BEFORE_CHILD_MOVEMENT,
BEFORE_CHILD_REPLACEMENT,
BEFORE_CHILD_ADDITION,
BEFORE_CHILD_REMOVAL -> {
// skip
}
CHILD_ADDED,
CHILD_REMOVED,
CHILD_REPLACED -> {
processChange(event.getParent(), event.getOldChild(), event.getChild())
}
CHILDREN_CHANGED -> {
if (!event.isGenericChange()) {
processChange(event.getParent(), event.getParent(), null)
}
}
CHILD_MOVED,
PROPERTY_CHANGED -> {
myModificationTracker.incCounter()
}
else -> LOG.error("Unknown code:" + event.getCode())
}
}
private fun processChange(parent: PsiElement?, child1: PsiElement?, child2: PsiElement?) {
try {
if (!isInsideCodeBlock(parent)) {
if (parent != null && parent.getContainingFile() is JetFile) {
myModificationTracker.incCounter()
}
else {
myModificationTracker.incOutOfCodeBlockModificationCounter()
}
return
}
if (containsClassesInside(child1) || (child2 != child1 && containsClassesInside(child2))) {
myModificationTracker.incCounter()
}
}
catch (e: PsiInvalidElementAccessException) {
myModificationTracker.incCounter() // Shall not happen actually, just a pre-release paranoia
}
}
class object {
private val LOG = Logger.getInstance("#org.jetbrains.jet.asJava.JetCodeBlockModificationListener")
private fun containsClassesInside(element: PsiElement?): Boolean {
if (element == null) return false
if (element is PsiClass) return true
var child = element.getFirstChild()
while (child != null) {
if (containsClassesInside(child)) return true
child = child!!.getNextSibling()
}
return false
}
private fun isInsideCodeBlock(element: PsiElement?): Boolean {
if (element is PsiFileSystemItem) return false
if (element == null || element.getParent() == null) return true
val blockDeclarationCandidate = JetPsiUtil.getTopmostParentOfTypes(
element,
javaClass<JetProperty>(),
javaClass<JetNamedFunction>())
when (blockDeclarationCandidate) {
is JetNamedFunction -> {
val function = blockDeclarationCandidate : JetNamedFunction
if (function.hasBlockBody() && function.getBodyExpression().isAncestorOf(element)) {
return true
}
if (function.hasDeclaredReturnType() && function.getInitializer().isAncestorOf(element)) {
return true
}
}
is JetProperty -> {
val property = blockDeclarationCandidate : JetProperty
for (accessor in property.getAccessors()) {
when {
accessor.getInitializer().isAncestorOf(element) -> return true
accessor.getBodyExpression().isAncestorOf(element) -> return true
}
}
}
}
return false
}
private fun PsiElement?.isAncestorOf(element: PsiElement) = PsiTreeUtil.isAncestor(this, element, false)
}
}
@@ -0,0 +1,419 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.google.common.collect.Lists;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.ClassFileViewProvider;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
import com.intellij.psi.impl.java.stubs.impl.PsiJavaFileStubImpl;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.PsiClassHolderFileStub;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.LightVirtualFile;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.CompilationErrorHandler;
import org.jetbrains.jet.codegen.KotlinCodegenFacade;
import org.jetbrains.jet.codegen.PackageCodegen;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.Progress;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import org.jetbrains.jet.lang.psi.JetScript;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.diagnostics.Diagnostics;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.org.objectweb.asm.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import static org.jetbrains.jet.lang.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
public class KotlinJavaFileStubProvider<T extends WithFileStubAndExtraDiagnostics> implements CachedValueProvider<T> {
@NotNull
public static KotlinJavaFileStubProvider<KotlinPackageLightClassData> createForPackageClass(
@NotNull final Project project,
@NotNull final FqName packageFqName,
@NotNull final GlobalSearchScope searchScope
) {
return new KotlinJavaFileStubProvider<KotlinPackageLightClassData>(
project,
false,
new StubGenerationStrategy<KotlinPackageLightClassData>() {
@NotNull
@Override
public LightClassConstructionContext getContext(@NotNull Collection<JetFile> files) {
return LightClassGenerationSupport.getInstance(project).getContextForPackage(files);
}
@NotNull
@Override
public Collection<JetFile> getFiles() {
// Don't memoize this, it can be called again after an out-of-code-block modification occurs,
// and the set of files changes
return LightClassGenerationSupport.getInstance(project).findFilesForPackage(packageFqName, searchScope);
}
@NotNull
@Override
public KotlinPackageLightClassData createLightClassData(
PsiJavaFileStub javaFileStub,
BindingContext bindingContext,
Diagnostics extraDiagnostics
) {
return new KotlinPackageLightClassData(javaFileStub, extraDiagnostics);
}
@NotNull
@Override
public FqName getPackageFqName() {
return packageFqName;
}
@Override
public GenerationState.GenerateClassFilter getGenerateClassFilter() {
return new GenerationState.GenerateClassFilter() {
@Override
public boolean shouldProcessClass(JetClassOrObject classOrObject) {
// Top-level classes and such should not be generated for performance reasons.
// Local classes in top-level functions must still be generated
return JetPsiUtil.isLocal(classOrObject);
}
@Override
public boolean shouldProcessScript(JetScript script) {
// Scripts yield top-level classes, and should not be generated
return false;
}
};
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
PackageCodegen codegen = state.getFactory().forPackage(packageFqName, files);
codegen.generate(CompilationErrorHandler.THROW_EXCEPTION);
state.getFactory().asList();
}
@Override
public String toString() {
return StubGenerationStrategy.class.getName() + " for package class";
}
}
);
}
@NotNull
public static KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData> createForDeclaredClass(@NotNull final JetClassOrObject classOrObject) {
return new KotlinJavaFileStubProvider<OutermostKotlinClassLightClassData>(
classOrObject.getProject(),
classOrObject.isLocal(),
new StubGenerationStrategy<OutermostKotlinClassLightClassData>() {
private JetFile getFile() {
return classOrObject.getContainingJetFile();
}
@NotNull
@Override
public LightClassConstructionContext getContext(@NotNull Collection<JetFile> files) {
return LightClassGenerationSupport.getInstance(classOrObject.getProject()).getContextForClassOrObject(classOrObject);
}
@NotNull
@Override
public OutermostKotlinClassLightClassData createLightClassData(
PsiJavaFileStub javaFileStub,
BindingContext bindingContext,
Diagnostics extraDiagnostics
) {
ClassDescriptor classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject);
if (classDescriptor == null) {
return new OutermostKotlinClassLightClassData(
javaFileStub, extraDiagnostics, FqName.ROOT, classOrObject,
null, Collections.<JetClassOrObject, InnerKotlinClassLightClassData>emptyMap()
);
}
FqName fqName = predictClassFqName(bindingContext, classDescriptor);
Collection<ClassDescriptor> allInnerClasses = CodegenBinding.getAllInnerClasses(bindingContext, classDescriptor);
Map<JetClassOrObject, InnerKotlinClassLightClassData> innerClassesMap = ContainerUtil.newHashMap();
for (ClassDescriptor innerClassDescriptor : allInnerClasses) {
PsiElement declaration = descriptorToDeclaration(innerClassDescriptor);
if (!(declaration instanceof JetClassOrObject)) continue;
JetClassOrObject innerClass = (JetClassOrObject) declaration;
InnerKotlinClassLightClassData innerLightClassData = new InnerKotlinClassLightClassData(
predictClassFqName(bindingContext, innerClassDescriptor),
innerClass,
innerClassDescriptor
);
innerClassesMap.put(innerClass, innerLightClassData);
}
return new OutermostKotlinClassLightClassData(
javaFileStub,
extraDiagnostics,
fqName,
classOrObject,
classDescriptor,
innerClassesMap
);
}
@NotNull
private FqName predictClassFqName(BindingContext bindingContext, ClassDescriptor classDescriptor) {
Type asmType = CodegenBinding.getAsmType(bindingContext, classDescriptor);
//noinspection ConstantConditions
return JvmClassName.byInternalName(asmType.getClassName().replace('.', '/')).getFqNameForClassNameWithoutDollars();
}
@NotNull
@Override
public Collection<JetFile> getFiles() {
return Collections.singletonList(getFile());
}
@NotNull
@Override
public FqName getPackageFqName() {
return getFile().getPackageFqName();
}
@Override
public GenerationState.GenerateClassFilter getGenerateClassFilter() {
return new GenerationState.GenerateClassFilter() {
@Override
public boolean shouldProcessClass(JetClassOrObject generatedClassOrObject) {
// Trivial: generate and analyze class we are interested in.
if (generatedClassOrObject == classOrObject) return true;
// Process all parent classes as they are context for current class
// Process child classes because they probably affect members (heuristic)
if (PsiTreeUtil.isAncestor(generatedClassOrObject, classOrObject, true) ||
PsiTreeUtil.isAncestor(classOrObject, generatedClassOrObject, true)) {
return true;
}
if (generatedClassOrObject.isLocal() && classOrObject.isLocal()) {
// Local classes should be process by CodegenAnnotatingVisitor to
// decide what class they should be placed in.
//
// Example:
// class A
// fun foo() {
// trait Z: A {}
// fun bar() {
// class <caret>O2: Z {}
// }
// }
// TODO: current method will process local classes in irrelevant declarations, it should be fixed.
PsiElement commonParent = PsiTreeUtil.findCommonParent(generatedClassOrObject, classOrObject);
return commonParent != null && !(commonParent instanceof PsiFile);
}
return false;
}
@Override
public boolean shouldProcessScript(JetScript script) {
// We generate all enclosing classes
return PsiTreeUtil.isAncestor(script, classOrObject, false);
}
};
}
@Override
public void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files) {
PackageCodegen packageCodegen = state.getFactory().forPackage(getPackageFqName(), files);
packageCodegen.generateClassOrObject(classOrObject);
state.getFactory().asList();
}
@Override
public String toString() {
return StubGenerationStrategy.class.getName() + " for explicit class " + classOrObject.getName();
}
}
);
}
private static final Logger LOG = Logger.getInstance(KotlinJavaFileStubProvider.class);
private final Project project;
private final StubGenerationStrategy<T> stubGenerationStrategy;
private final boolean local;
private KotlinJavaFileStubProvider(
@NotNull Project project,
boolean local,
@NotNull StubGenerationStrategy<T> stubGenerationStrategy
) {
this.project = project;
this.stubGenerationStrategy = stubGenerationStrategy;
this.local = local;
}
@Nullable
@Override
public Result<T> compute() {
FqName packageFqName = stubGenerationStrategy.getPackageFqName();
Collection<JetFile> files = stubGenerationStrategy.getFiles();
checkForBuiltIns(packageFqName, files);
LightClassConstructionContext context = stubGenerationStrategy.getContext(files);
PsiJavaFileStub javaFileStub = createJavaFileStub(packageFqName, getRepresentativeVirtualFile(files));
BindingContext bindingContext;
BindingTraceContext forExtraDiagnostics = new BindingTraceContext();
try {
Stack<StubElement> stubStack = new Stack<StubElement>();
stubStack.push(javaFileStub);
GenerationState state = new GenerationState(
project,
new KotlinLightClassBuilderFactory(stubStack),
Progress.DEAF,
context.getModule(),
context.getBindingContext(),
Lists.newArrayList(files),
/*disable not-null assertions*/false, false,
/*generateClassFilter=*/stubGenerationStrategy.getGenerateClassFilter(),
/*disableInline=*/false,
/*disableOptimization=*/false,
null,
null,
forExtraDiagnostics,
null
);
KotlinCodegenFacade.prepareForCompilation(state);
bindingContext = state.getBindingContext();
stubGenerationStrategy.generate(state, files);
StubElement pop = stubStack.pop();
if (pop != javaFileStub) {
LOG.error("Unbalanced stack operations: " + pop);
}
}
catch (ProcessCanceledException e) {
throw e;
}
catch (RuntimeException e) {
logErrorWithOSInfo(e, packageFqName, null);
throw e;
}
Diagnostics extraDiagnostics = forExtraDiagnostics.getBindingContext().getDiagnostics();
return Result.create(
stubGenerationStrategy.createLightClassData(javaFileStub, bindingContext, extraDiagnostics),
local ? PsiModificationTracker.MODIFICATION_COUNT : PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT
);
}
@NotNull
private PsiJavaFileStub createJavaFileStub(@NotNull final FqName packageFqName, @NotNull VirtualFile virtualFile) {
PsiManager manager = PsiManager.getInstance(project);
final PsiJavaFileStubImpl javaFileStub = new PsiJavaFileStubImpl(packageFqName.asString(), true);
javaFileStub.setPsiFactory(new ClsWrapperStubPsiFactory());
ClsFileImpl fakeFile =
new ClsFileImpl((PsiManagerImpl) manager, new ClassFileViewProvider(manager, virtualFile)) {
@NotNull
@Override
public PsiClassHolderFileStub getStub() {
return javaFileStub;
}
@NotNull
@Override
public String getPackageName() {
return packageFqName.asString();
}
};
fakeFile.setPhysical(false);
javaFileStub.setPsi(fakeFile);
return javaFileStub;
}
@NotNull
private static VirtualFile getRepresentativeVirtualFile(@NotNull Collection<JetFile> files) {
JetFile firstFile = files.iterator().next();
VirtualFile virtualFile = files.size() == 1 ? firstFile.getVirtualFile() : new LightVirtualFile();
assert virtualFile != null : "No virtual file for " + firstFile;
return virtualFile;
}
private static void checkForBuiltIns(@NotNull FqName fqName, @NotNull Collection<JetFile> files) {
for (JetFile file : files) {
if (LightClassUtil.belongsToKotlinBuiltIns(file)) {
// We may not fail later due to some luck, but generating JetLightClasses for built-ins is a bad idea anyways
// If it fails later, there will be an exception logged
logErrorWithOSInfo(null, fqName, file.getVirtualFile());
}
}
}
private static void logErrorWithOSInfo(@Nullable Throwable cause, @NotNull FqName fqName, @Nullable VirtualFile virtualFile) {
String path = virtualFile == null ? "<null>" : virtualFile.getPath();
LOG.error(
"Could not generate LightClass for " + fqName + " declared in " + path + "\n" +
"built-ins dir URL is " + LightClassUtil.getBuiltInsDirUrl() + "\n" +
"System: " + SystemInfo.OS_NAME + " " + SystemInfo.OS_VERSION + " Java Runtime: " + SystemInfo.JAVA_RUNTIME_VERSION,
cause);
}
private interface StubGenerationStrategy<T extends WithFileStubAndExtraDiagnostics> {
@NotNull Collection<JetFile> getFiles();
@NotNull FqName getPackageFqName();
@NotNull LightClassConstructionContext getContext(@NotNull Collection<JetFile> files);
@NotNull T createLightClassData(PsiJavaFileStub javaFileStub, BindingContext bindingContext, Diagnostics extraDiagnostics);
GenerationState.GenerateClassFilter getGenerateClassFilter();
void generate(@NotNull GenerationState state, @NotNull Collection<JetFile> files);
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.psi.PsiClass;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.psi.JetClassOrObject
public trait KotlinLightClass : PsiClass, KotlinLightElement<JetClassOrObject, PsiClass> {
val fqName: FqName
}
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.psi.stubs.StubElement;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.codegen.ClassBuilder;
import org.jetbrains.jet.codegen.ClassBuilderFactory;
import org.jetbrains.jet.codegen.ClassBuilderMode;
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
/*package*/ class KotlinLightClassBuilderFactory implements ClassBuilderFactory {
private final Stack<StubElement> stubStack;
public KotlinLightClassBuilderFactory(Stack<StubElement> stubStack) {
this.stubStack = stubStack;
}
@NotNull
@Override
public ClassBuilderMode getClassBuilderMode() {
return ClassBuilderMode.LIGHT_CLASSES;
}
@NotNull
@Override
public ClassBuilder newClassBuilder(@NotNull JvmDeclarationOrigin origin) {
return new StubClassBuilder(stubStack);
}
@Override
public String asText(ClassBuilder builder) {
throw new UnsupportedOperationException("asText is not implemented"); // TODO
}
@Override
public byte[] asBytes(ClassBuilder builder) {
throw new UnsupportedOperationException("asBytes is not implemented"); // TODO
}
}
@@ -0,0 +1,95 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.reference.SoftReference;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collection;
class KotlinLightClassForAnonymousDeclaration extends KotlinLightClassForExplicitDeclaration implements PsiAnonymousClass {
private static final Logger LOG = Logger.getInstance(KotlinLightClassForAnonymousDeclaration.class);
private SoftReference<PsiClassType> cachedBaseType = null;
KotlinLightClassForAnonymousDeclaration(@NotNull PsiManager manager, @NotNull FqName name, @NotNull JetClassOrObject classOrObject) {
super(manager, name, classOrObject);
}
@NotNull
@Override
public PsiJavaCodeReferenceElement getBaseClassReference() {
Project project = classOrObject.getProject();
return JavaPsiFacade.getElementFactory(project).createReferenceElementByFQClassName(
getFirstSupertypeFQName(), GlobalSearchScope.allScope(project)
);
}
private String getFirstSupertypeFQName() {
ClassDescriptor descriptor = getDescriptor();
if (descriptor == null) return CommonClassNames.JAVA_LANG_OBJECT;
Collection<JetType> superTypes = descriptor.getTypeConstructor().getSupertypes();
if (superTypes.isEmpty()) return CommonClassNames.JAVA_LANG_OBJECT;
JetType superType = superTypes.iterator().next();
DeclarationDescriptor superClassDescriptor = superType.getConstructor().getDeclarationDescriptor();
if (superClassDescriptor == null) {
LOG.error("No declaration descriptor for supertype " + superType + " of " + getDescriptor());
// return java.lang.Object for recovery
return CommonClassNames.JAVA_LANG_OBJECT;
}
return DescriptorUtils.getFqName(superClassDescriptor).asString();
}
@NotNull
@Override
public synchronized PsiClassType getBaseClassType() {
PsiClassType type = null;
if (cachedBaseType != null) type = cachedBaseType.get();
if (type != null && type.isValid()) return type;
type = JavaPsiFacade.getInstance(classOrObject.getProject()).getElementFactory().createType(getBaseClassReference());
cachedBaseType = new SoftReference<PsiClassType>(type);
return type;
}
@Nullable
@Override
public PsiExpressionList getArgumentList() {
return null;
}
@Override
public boolean isInQualifiedNew() {
return false;
}
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.PsiManager
import org.jetbrains.jet.lang.resolve.name.FqName
import org.jetbrains.jet.lang.psi.JetEnumEntry
import com.intellij.psi.PsiEnumConstantInitializer
import com.intellij.psi.PsiEnumConstant
public class KotlinLightClassForEnumEntry(
psiManager: PsiManager,
fqName: FqName,
enumEntry: JetEnumEntry,
private val enumConstant: PsiEnumConstant
): KotlinLightClassForAnonymousDeclaration(psiManager, fqName, enumEntry), PsiEnumConstantInitializer {
override fun getEnumConstant(): PsiEnumConstant = enumConstant
}
@@ -0,0 +1,604 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NullableLazyValue;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub;
import com.intellij.psi.impl.light.LightClass;
import com.intellij.psi.impl.light.LightMethod;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.stubs.PsiClassHolderFileStub;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.codegen.binding.PsiCodegenPredictor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.resolve.name.FqNameUnsafe;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.lexer.JetModifierKeywordToken;
import org.jetbrains.jet.plugin.JetLanguage;
import javax.swing.*;
import java.util.Collection;
import java.util.List;
import static org.jetbrains.jet.lexer.JetTokens.*;
public class KotlinLightClassForExplicitDeclaration extends KotlinWrappingLightClass implements JetJavaMirrorMarker {
private final static Key<CachedValue<OutermostKotlinClassLightClassData>> JAVA_API_STUB = Key.create("JAVA_API_STUB");
@Nullable
public static KotlinLightClassForExplicitDeclaration create(@NotNull PsiManager manager, @NotNull JetClassOrObject classOrObject) {
if (LightClassUtil.belongsToKotlinBuiltIns(classOrObject.getContainingJetFile())) {
return null;
}
FqName fqName = predictFqName(classOrObject);
if (fqName == null) return null;
if (classOrObject instanceof JetObjectDeclaration && ((JetObjectDeclaration) classOrObject).isObjectLiteral()) {
return new KotlinLightClassForAnonymousDeclaration(manager, fqName, classOrObject);
}
return new KotlinLightClassForExplicitDeclaration(manager, fqName, classOrObject);
}
@Nullable
private static FqName predictFqName(@NotNull JetClassOrObject classOrObject) {
if (classOrObject.isLocal()) {
LightClassDataForKotlinClass data = getLightClassDataExactly(classOrObject);
return data == null ? null : data.getJvmQualifiedName();
}
String internalName = PsiCodegenPredictor.getPredefinedJvmInternalName(classOrObject);
return internalName == null ? null : JvmClassName.byInternalName(internalName).getFqNameForClassNameWithoutDollars();
}
private final FqName classFqName; // FqName of (possibly inner) class
protected final JetClassOrObject classOrObject;
private PsiClass delegate;
private final NullableLazyValue<PsiElement> parent = new NullableLazyValue<PsiElement>() {
@Nullable
@Override
protected PsiElement compute() {
if (classOrObject.isLocal()) {
//noinspection unchecked
PsiElement declaration = JetPsiUtil.getTopmostParentOfTypes(
classOrObject,
JetNamedFunction.class, JetProperty.class, JetClassInitializer.class, JetParameter.class
);
if (declaration instanceof JetParameter) {
declaration = PsiTreeUtil.getParentOfType(declaration, JetNamedDeclaration.class);
}
if (declaration instanceof JetNamedFunction) {
JetNamedFunction function = (JetNamedFunction) declaration;
return getParentByPsiMethod(LightClassUtil.getLightClassMethod(function), function.getName(), false);
}
// Represent the property as a fake method with the same name
if (declaration instanceof JetProperty) {
JetProperty property = (JetProperty) declaration;
return getParentByPsiMethod(LightClassUtil.getLightClassPropertyMethods(property).getGetter(), property.getName(), true);
}
if (declaration instanceof JetClassInitializer) {
PsiElement parent = declaration.getParent();
PsiElement grandparent = parent.getParent();
if (parent instanceof JetClassBody && grandparent instanceof JetClassOrObject) {
return LightClassUtil.getPsiClass((JetClassOrObject) grandparent);
}
}
if (declaration instanceof JetClass) {
return LightClassUtil.getPsiClass((JetClass) declaration);
}
}
return classOrObject.getParent() == classOrObject.getContainingFile() ? getContainingFile() : getContainingClass();
}
private PsiElement getParentByPsiMethod(PsiMethod method, final String name, boolean forceMethodWrapping) {
if (method == null || name == null) return null;
PsiClass containingClass = method.getContainingClass();
if (containingClass == null) return null;
final String currentFileName = classOrObject.getContainingFile().getName();
boolean createWrapper = forceMethodWrapping;
// Use PsiClass wrapper instead of package light class to avoid names like "FooPackage" in Type Hierarchy and related views
if (containingClass instanceof KotlinLightClassForPackage) {
containingClass = new LightClass(containingClass, JetLanguage.INSTANCE) {
@Nullable
@Override
public String getName() {
return currentFileName;
}
};
createWrapper = true;
}
if (createWrapper) {
return new LightMethod(myManager, method, containingClass, JetLanguage.INSTANCE) {
@Override
public PsiElement getParent() {
return getContainingClass();
}
@NotNull
@Override
public String getName() {
return name;
}
};
}
return method;
}
};
@Nullable
private PsiModifierList modifierList;
private final NullableLazyValue<PsiTypeParameterList> typeParameterList = new NullableLazyValue<PsiTypeParameterList>() {
@Nullable
@Override
protected PsiTypeParameterList compute() {
return LightClassUtil.buildLightTypeParameterList(KotlinLightClassForExplicitDeclaration.this, classOrObject);
}
};
KotlinLightClassForExplicitDeclaration(
@NotNull PsiManager manager,
@NotNull FqName name,
@NotNull JetClassOrObject classOrObject
) {
super(manager);
this.classFqName = name;
this.classOrObject = classOrObject;
}
@Override
@NotNull
public JetClassOrObject getOrigin() {
return classOrObject;
}
@NotNull
@Override
public FqName getFqName() {
return classFqName;
}
@NotNull
@Override
public PsiElement copy() {
return new KotlinLightClassForExplicitDeclaration(getManager(), classFqName, (JetClassOrObject) classOrObject.copy());
}
@NotNull
@Override
public PsiClass getDelegate() {
if (delegate == null) {
PsiJavaFileStub javaFileStub = getJavaFileStub();
PsiClass psiClass = LightClassUtil.findClass(classFqName, javaFileStub);
if (psiClass == null) {
JetClassOrObject outermostClassOrObject = getOutermostClassOrObject(classOrObject);
throw new IllegalStateException("Class was not found " + classFqName + "\n" +
"in " + outermostClassOrObject.getContainingFile().getText() + "\n" +
"stub: \n" + javaFileStub.getPsi().getText());
}
delegate = psiClass;
}
return delegate;
}
@NotNull
private PsiJavaFileStub getJavaFileStub() {
return getLightClassData().getJavaFileStub();
}
@Nullable
protected final ClassDescriptor getDescriptor() {
LightClassDataForKotlinClass data = getLightClassDataExactly(classOrObject);
return data != null ? data.getDescriptor() : null;
}
@NotNull
private OutermostKotlinClassLightClassData getLightClassData() {
return getLightClassData(classOrObject);
}
@NotNull
public static OutermostKotlinClassLightClassData getLightClassData(@NotNull JetClassOrObject classOrObject) {
JetClassOrObject outermostClassOrObject = getOutermostClassOrObject(classOrObject);
return CachedValuesManager.getManager(classOrObject.getProject()).getCachedValue(
outermostClassOrObject,
JAVA_API_STUB,
KotlinJavaFileStubProvider.createForDeclaredClass(outermostClassOrObject),
/*trackValue = */false
);
}
@Nullable
private static LightClassDataForKotlinClass getLightClassDataExactly(JetClassOrObject classOrObject) {
OutermostKotlinClassLightClassData data = getLightClassData(classOrObject);
return data.getClassOrObject().equals(classOrObject) ? data : data.getAllInnerClasses().get(classOrObject);
}
@NotNull
private static JetClassOrObject getOutermostClassOrObject(@NotNull JetClassOrObject classOrObject) {
JetClassOrObject outermostClass = JetPsiUtil.getOutermostClassOrObject(classOrObject);
if (outermostClass == null) {
throw new IllegalStateException("Attempt to build a light class for a local class: " + classOrObject.getText());
}
else {
return outermostClass;
}
}
private final NullableLazyValue<PsiFile> _containingFile = new NullableLazyValue<PsiFile>() {
@Nullable
@Override
protected PsiFile compute() {
VirtualFile virtualFile = classOrObject.getContainingFile().getVirtualFile();
assert virtualFile != null : "No virtual file for " + classOrObject.getText();
return new ClsFileImpl((PsiManagerImpl) getManager(), new ClassFileViewProvider(getManager(), virtualFile)) {
@NotNull
@Override
public String getPackageName() {
return classOrObject.getContainingJetFile().getPackageFqName().asString();
}
@NotNull
@Override
public PsiClassHolderFileStub getStub() {
return getJavaFileStub();
}
@SuppressWarnings("Contract")
@Override
public boolean processDeclarations(
@NotNull PsiScopeProcessor processor,
@NotNull ResolveState state,
PsiElement lastParent,
@NotNull PsiElement place
) {
if (!super.processDeclarations(processor, state, lastParent, place)) return false;
// We have to explicitly process package declarations if current file belongs to default package
// so that Java resolve can find classes located in that package
String packageName = getPackageName();
if (!packageName.isEmpty()) return true;
PsiPackage aPackage = JavaPsiFacade.getInstance(myManager.getProject()).findPackage(packageName);
if (aPackage != null && !aPackage.processDeclarations(processor, state, null, place)) return false;
return true;
}
};
}
};
@Override
public PsiFile getContainingFile() {
return _containingFile.getValue();
}
@NotNull
@Override
public PsiElement getNavigationElement() {
return classOrObject;
}
@Override
public boolean isEquivalentTo(PsiElement another) {
return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName());
}
@Override
public Icon getElementIcon(int flags) {
throw new UnsupportedOperationException("This should be done byt JetIconProvider");
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
KotlinLightClassForExplicitDeclaration aClass = (KotlinLightClassForExplicitDeclaration) o;
if (!classFqName.equals(aClass.classFqName)) return false;
return true;
}
@Override
public int hashCode() {
return classFqName.hashCode();
}
@Nullable
@Override
public PsiClass getContainingClass() {
if (classOrObject.getParent() == classOrObject.getContainingFile()) return null;
return super.getContainingClass();
}
@Nullable
@Override
public PsiElement getParent() {
return parent.getValue();
}
@Override
public PsiElement getContext() {
return getParent();
}
@Nullable
@Override
public PsiTypeParameterList getTypeParameterList() {
return typeParameterList.getValue();
}
@NotNull
@Override
public PsiTypeParameter[] getTypeParameters() {
PsiTypeParameterList typeParameterList = getTypeParameterList();
return typeParameterList == null ? PsiTypeParameter.EMPTY_ARRAY : typeParameterList.getTypeParameters();
}
@Nullable
@Override
public String getName() {
return classFqName.shortName().asString();
}
@Nullable
@Override
public String getQualifiedName() {
return classFqName.asString();
}
@NotNull
@Override
public PsiModifierList getModifierList() {
if (modifierList == null) {
modifierList = new KotlinLightModifierList(this.getManager(), computeModifiers()) {
@Override
public PsiAnnotationOwner getDelegate() {
return KotlinLightClassForExplicitDeclaration.this.getDelegate().getModifierList();
}
};
}
return modifierList;
}
@NotNull
private String[] computeModifiers() {
Collection<String> psiModifiers = Sets.newHashSet();
// PUBLIC, PROTECTED, PRIVATE, ABSTRACT, FINAL
//noinspection unchecked
List<Pair<JetModifierKeywordToken, String>> jetTokenToPsiModifier = Lists.newArrayList(
Pair.create(PUBLIC_KEYWORD, PsiModifier.PUBLIC),
Pair.create(INTERNAL_KEYWORD, PsiModifier.PUBLIC),
Pair.create(PROTECTED_KEYWORD, PsiModifier.PROTECTED),
Pair.create(FINAL_KEYWORD, PsiModifier.FINAL));
for (Pair<JetModifierKeywordToken, String> tokenAndModifier : jetTokenToPsiModifier) {
if (classOrObject.hasModifier(tokenAndModifier.first)) {
psiModifiers.add(tokenAndModifier.second);
}
}
if (classOrObject.hasModifier(PRIVATE_KEYWORD)) {
// Top-level private class has PUBLIC visibility in Java
// Nested private class has PRIVATE visibility
psiModifiers.add(classOrObject.isTopLevel() ? PsiModifier.PUBLIC : PsiModifier.PRIVATE);
}
if (!psiModifiers.contains(PsiModifier.PRIVATE) && !psiModifiers.contains(PsiModifier.PROTECTED)) {
psiModifiers.add(PsiModifier.PUBLIC); // For internal (default) visibility
}
// FINAL
if (isAbstract(classOrObject)) {
psiModifiers.add(PsiModifier.ABSTRACT);
}
else if (!(classOrObject.hasModifier(OPEN_KEYWORD) || (classOrObject instanceof JetClass && ((JetClass) classOrObject).isEnum()))) {
psiModifiers.add(PsiModifier.FINAL);
}
if (!classOrObject.isTopLevel() && !classOrObject.hasModifier(INNER_KEYWORD)) {
psiModifiers.add(PsiModifier.STATIC);
}
return ArrayUtil.toStringArray(psiModifiers);
}
private boolean isAbstract(@NotNull JetClassOrObject object) {
return object.hasModifier(ABSTRACT_KEYWORD) || isInterface();
}
@Override
public boolean hasModifierProperty(@NonNls @NotNull String name) {
return getModifierList().hasModifierProperty(name);
}
@Override
public boolean isDeprecated() {
JetModifierList jetModifierList = classOrObject.getModifierList();
if (jetModifierList == null) {
return false;
}
ClassDescriptor deprecatedAnnotation = KotlinBuiltIns.getInstance().getDeprecatedAnnotation();
String deprecatedName = deprecatedAnnotation.getName().asString();
FqNameUnsafe deprecatedFqName = DescriptorUtils.getFqName(deprecatedAnnotation);
for (JetAnnotationEntry annotationEntry : jetModifierList.getAnnotationEntries()) {
JetTypeReference typeReference = annotationEntry.getTypeReference();
if (typeReference == null) continue;
JetTypeElement typeElement = typeReference.getTypeElement();
if (!(typeElement instanceof JetUserType)) continue; // If it's not a user type, it's definitely not a ref to deprecated
FqName fqName = JetPsiUtil.toQualifiedName((JetUserType) typeElement);
if (fqName == null) continue;
if (deprecatedFqName.equals(fqName.toUnsafe())) return true;
if (deprecatedName.equals(fqName.asString())) return true;
}
return false;
}
@Override
public boolean isInterface() {
if (!(classOrObject instanceof JetClass)) return false;
JetClass jetClass = (JetClass) classOrObject;
return jetClass.isTrait() || jetClass.isAnnotation();
}
@Override
public boolean isAnnotationType() {
return classOrObject instanceof JetClass && ((JetClass) classOrObject).isAnnotation();
}
@Override
public boolean isEnum() {
return classOrObject instanceof JetClass && ((JetClass) classOrObject).isEnum();
}
@Override
public boolean hasTypeParameters() {
return classOrObject instanceof JetClass && !((JetClass) classOrObject).getTypeParameters().isEmpty();
}
@Override
public boolean isValid() {
return classOrObject.isValid();
}
@Override
public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
// Java inheritor check doesn't work when trait (interface in Java) subclasses Java class and for Kotlin local classes
if (baseClass instanceof KotlinLightClassForExplicitDeclaration || (isInterface() && !baseClass.isInterface())) {
String qualifiedName;
if (baseClass instanceof KotlinLightClassForExplicitDeclaration) {
ClassDescriptor baseDescriptor = ((KotlinLightClassForExplicitDeclaration) baseClass).getDescriptor();
qualifiedName = baseDescriptor != null ? DescriptorUtils.getFqName(baseDescriptor).asString() : null;
}
else {
qualifiedName = baseClass.getQualifiedName();
}
ClassDescriptor thisDescriptor = getDescriptor();
return qualifiedName != null
&& thisDescriptor != null
&& checkSuperTypeByFQName(thisDescriptor, qualifiedName, checkDeep);
}
return super.isInheritor(baseClass, checkDeep);
}
@Override
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
throw new IncorrectOperationException("Cannot modify compiled kotlin element");
}
@Override
public String toString() {
try {
return KotlinLightClass.class.getSimpleName() + ":" + getQualifiedName();
}
catch (Throwable e) {
return KotlinLightClass.class.getSimpleName() + ":" + e.toString();
}
}
@NotNull
@Override
public List<PsiClass> getOwnInnerClasses() {
return KotlinPackage.filterNotNull(
KotlinPackage.map(
getDelegate().getInnerClasses(),
new Function1<PsiClass, PsiClass>() {
@Override
public PsiClass invoke(PsiClass aClass) {
JetClassOrObject declaration = (JetClassOrObject) ClsWrapperStubPsiFactory.getOriginalDeclaration(aClass);
return declaration != null ? KotlinLightClassForExplicitDeclaration.create(myManager, declaration) : null;
}
}
)
);
}
private static boolean checkSuperTypeByFQName(@NotNull ClassDescriptor classDescriptor, @NotNull String qualifiedName, Boolean deep) {
if (CommonClassNames.JAVA_LANG_OBJECT.equals(qualifiedName)) return true;
if (qualifiedName.equals(DescriptorUtils.getFqName(classDescriptor).asString())) return true;
for (JetType superType : classDescriptor.getTypeConstructor().getSupertypes()) {
ClassifierDescriptor superDescriptor = superType.getConstructor().getDeclarationDescriptor();
if (superDescriptor instanceof ClassDescriptor) {
if (qualifiedName.equals(DescriptorUtils.getFqName(superDescriptor).asString())) return true;
if (deep) {
if (checkSuperTypeByFQName((ClassDescriptor)superDescriptor, qualifiedName, true)) {
return true;
}
}
}
}
return false;
}
}
@@ -0,0 +1,430 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.google.common.collect.Sets;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightEmptyImplementsList;
import com.intellij.psi.impl.light.LightModifierList;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.CachedValue;
import com.intellij.psi.util.CachedValueProvider;
import com.intellij.psi.util.CachedValuesManager;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.util.containers.SLRUCache;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.ReadOnly;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.java.jetAsJava.JetJavaMirrorMarker;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.plugin.JetLanguage;
import javax.swing.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
public class KotlinLightClassForPackage extends KotlinWrappingLightClass implements JetJavaMirrorMarker {
public static class FileStubCache {
@NotNull
public static FileStubCache getInstance(@NotNull Project project) {
return ServiceManager.getService(project, FileStubCache.class);
}
private static final class Key {
private final FqName fqName;
private final GlobalSearchScope searchScope;
private Key(
@NotNull FqName fqName,
@NotNull GlobalSearchScope searchScope
) {
this.fqName = fqName;
this.searchScope = searchScope;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
if (!fqName.equals(key.fqName)) return false;
if (!searchScope.equals(key.searchScope)) return false;
return true;
}
@Override
public int hashCode() {
int result = fqName.hashCode();
result = 31 * result + searchScope.hashCode();
return result;
}
}
private final class CacheData {
private final SLRUCache<Key, CachedValue<KotlinPackageLightClassData>> cache = new SLRUCache<Key, CachedValue<KotlinPackageLightClassData>>(20, 30) {
@NotNull
@Override
public CachedValue<KotlinPackageLightClassData> createValue(Key key) {
KotlinJavaFileStubProvider<KotlinPackageLightClassData> stubProvider =
KotlinJavaFileStubProvider.createForPackageClass(project, key.fqName, key.searchScope);
return CachedValuesManager.getManager(project).createCachedValue(stubProvider, /*trackValue = */false);
}
};
}
private final Project project;
private final CachedValue<CacheData> cachedValue;
public FileStubCache(@NotNull Project project) {
this.project = project;
this.cachedValue = CachedValuesManager.getManager(project).createCachedValue(
new CachedValueProvider<CacheData>() {
@Nullable
@Override
public Result<CacheData> compute() {
return Result.create(new CacheData(), PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT);
}
},
/*trackValue = */ false
);
}
@NotNull
public CachedValue<KotlinPackageLightClassData> get(
@NotNull FqName qualifiedName,
@NotNull GlobalSearchScope searchScope
) {
synchronized (cachedValue) {
return cachedValue.getValue().cache.get(new Key(qualifiedName, searchScope));
}
}
}
private final FqName packageFqName;
private final FqName packageClassFqName; // derived from packageFqName
private final GlobalSearchScope searchScope;
private final Collection<JetFile> files;
private final int hashCode;
private final CachedValue<KotlinPackageLightClassData> lightClassDataCache;
private final PsiModifierList modifierList;
private final LightEmptyImplementsList implementsList;
private KotlinLightClassForPackage(
@NotNull PsiManager manager,
@NotNull FqName packageFqName,
@NotNull GlobalSearchScope searchScope,
@NotNull Collection<JetFile> files
) {
super(manager);
this.modifierList = new LightModifierList(manager, JetLanguage.INSTANCE, PsiModifier.PUBLIC, PsiModifier.FINAL);
this.implementsList = new LightEmptyImplementsList(manager);
this.packageFqName = packageFqName;
this.packageClassFqName = PackageClassUtils.getPackageClassFqName(packageFqName);
this.searchScope = searchScope;
assert !files.isEmpty() : "No files for package " + packageFqName;
this.files = Sets.newHashSet(files); // needed for hashCode
this.hashCode = computeHashCode();
this.lightClassDataCache = FileStubCache.getInstance(getProject()).get(packageFqName, searchScope);
}
@Nullable
public static KotlinLightClassForPackage create(
@NotNull PsiManager manager,
@NotNull FqName qualifiedName,
@NotNull GlobalSearchScope searchScope,
@NotNull Collection<JetFile> files // this is redundant, but computing it multiple times is costly
) {
for (JetFile file : files) {
if (LightClassUtil.belongsToKotlinBuiltIns(file)) return null;
}
return new KotlinLightClassForPackage(manager, qualifiedName, searchScope, files);
}
private static boolean allValid(Collection<JetFile> files) {
for (JetFile file : files) {
if (!file.isValid()) return false;
}
return true;
}
@Nullable
@Override
public JetClassOrObject getOrigin() {
return null;
}
@Nullable
@Override
public PsiModifierList getModifierList() {
return modifierList;
}
@Override
public boolean hasModifierProperty(@NonNls @NotNull String name) {
return modifierList.hasModifierProperty(name);
}
@Override
public boolean isDeprecated() {
return false;
}
@Override
public boolean isInterface() {
return false;
}
@Override
public boolean isAnnotationType() {
return false;
}
@Override
public boolean isEnum() {
return false;
}
@Nullable
@Override
public PsiClass getContainingClass() {
return null;
}
@Override
public boolean hasTypeParameters() {
return false;
}
@NotNull
@Override
public PsiTypeParameter[] getTypeParameters() {
return PsiTypeParameter.EMPTY_ARRAY;
}
@Nullable
@Override
public PsiTypeParameterList getTypeParameterList() {
return null;
}
@Nullable
@Override
public PsiDocComment getDocComment() {
return null;
}
@Nullable
@Override
public PsiReferenceList getImplementsList() {
return implementsList;
}
@NotNull
@Override
public PsiClassType[] getImplementsListTypes() {
return PsiClassType.EMPTY_ARRAY;
}
@Nullable
@Override
public PsiReferenceList getExtendsList() {
// TODO: Find a way to return just Object
return super.getExtendsList();
}
@NotNull
@Override
public PsiClassType[] getExtendsListTypes() {
// TODO see getExtendsList()
return super.getExtendsListTypes();
}
@Nullable
@Override
public PsiClass getSuperClass() {
// TODO see getExtendsList()
return super.getSuperClass();
}
@NotNull
@Override
public PsiClass[] getSupers() {
// TODO see getExtendsList()
return super.getSupers();
}
@NotNull
@Override
public PsiClassType[] getSuperTypes() {
// TODO see getExtendsList()
return super.getSuperTypes();
}
@Override
public PsiClass[] getInterfaces() {
return PsiClass.EMPTY_ARRAY;
}
@NotNull
@Override
public PsiClass[] getInnerClasses() {
return PsiClass.EMPTY_ARRAY;
}
@NotNull
@Override
public List<PsiClass> getOwnInnerClasses() {
return Collections.emptyList();
}
@NotNull
@Override
public PsiClass[] getAllInnerClasses() {
return PsiClass.EMPTY_ARRAY;
}
@NotNull
@Override
public PsiClassInitializer[] getInitializers() {
return PsiClassInitializer.EMPTY_ARRAY;
}
@Nullable
@Override
public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) {
return null;
}
@NotNull
@Override
public FqName getFqName() {
return packageClassFqName;
}
@Nullable
@Override
public String getName() {
return packageClassFqName.shortName().asString();
}
@Nullable
@Override
public String getQualifiedName() {
return packageClassFqName.asString();
}
@Override
public boolean isValid() {
return allValid(files);
}
@NotNull
@Override
public PsiElement copy() {
return new KotlinLightClassForPackage(getManager(), packageFqName, searchScope, files);
}
@NotNull
@Override
public PsiClass getDelegate() {
PsiClass psiClass = LightClassUtil.findClass(packageClassFqName, lightClassDataCache.getValue().getJavaFileStub());
if (psiClass == null) {
throw new IllegalStateException("Package class was not found " + packageFqName);
}
return psiClass;
}
@NotNull
@Override
public PsiElement getNavigationElement() {
return files.iterator().next();
}
@Override
public boolean isEquivalentTo(PsiElement another) {
return another instanceof PsiClass && Comparing.equal(((PsiClass) another).getQualifiedName(), getQualifiedName());
}
@Override
public Icon getElementIcon(int flags) {
throw new UnsupportedOperationException("This should be done byt JetIconProvider");
}
@Override
public int hashCode() {
return hashCode;
}
private int computeHashCode() {
int result = getManager().hashCode();
result = 31 * result + files.hashCode();
result = 31 * result + packageFqName.hashCode();
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) {
return false;
}
KotlinLightClassForPackage lightClass = (KotlinLightClassForPackage) obj;
if (this.hashCode != lightClass.hashCode) return false;
if (getManager() != lightClass.getManager()) return false;
if (!files.equals(lightClass.files)) return false;
if (!packageFqName.equals(lightClass.packageFqName)) return false;
return true;
}
@Override
public String toString() {
try {
return KotlinLightClassForPackage.class.getSimpleName() + ":" + getQualifiedName();
}
catch (Throwable e) {
return KotlinLightClassForPackage.class.getSimpleName() + ":" + e.toString();
}
}
//NOTE: this is only needed to compute plugin module info
@NotNull
@ReadOnly
public final Collection<JetFile> getFiles() {
return files;
}
}
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import org.jetbrains.jet.lang.psi.JetDeclaration
import com.intellij.psi.PsiElement
public trait KotlinLightElement<T : JetDeclaration, D : PsiElement> {
public val origin: T?
public val delegate: D
}
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.*
import org.jetbrains.jet.lang.psi.JetEnumEntry
class KotlinLightEnumConstant(
manager: PsiManager,
origin: JetEnumEntry,
enumConstant: PsiEnumConstant,
containingClass: PsiClass,
private val initializingClass: PsiEnumConstantInitializer?
) : KotlinLightField<JetEnumEntry, PsiEnumConstant>(manager, origin, enumConstant, containingClass), PsiEnumConstant {
override fun copy() = KotlinLightEnumConstant(getManager()!!, getOrigin(), getDelegate(), getContainingClass()!!, initializingClass)
// NOTE: we don't use "delegation by" because the compiler would generate method calls to ALL of PsiEnumConstant members,
// but we need only members whose implementations are not present in KotlinLightField
override fun getArgumentList(): PsiExpressionList? = getDelegate().getArgumentList()
override fun getInitializingClass(): PsiEnumConstantInitializer? = initializingClass
override fun getOrCreateInitializingClass(): PsiEnumConstantInitializer =
initializingClass ?: throw UnsupportedOperationException("Can't create enum constant body: ${getDelegate().getName()}")
override fun resolveConstructor(): PsiMethod? = getDelegate().resolveConstructor()
override fun resolveMethod(): PsiMethod? = getDelegate().resolveMethod()
override fun resolveMethodGenerics(): JavaResolveResult = getDelegate().resolveMethodGenerics()
}
@@ -0,0 +1,177 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.SearchScope;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetDeclaration;
import org.jetbrains.jet.plugin.JetLanguage;
// Copied from com.intellij.psi.impl.light.LightField
public abstract class KotlinLightField<T extends JetDeclaration, D extends PsiField> extends LightElement
implements PsiField, KotlinLightElement<T, D> {
private final T origin;
private final D delegate;
private final PsiClass containingClass;
public KotlinLightField(@NotNull PsiManager manager, @NotNull T origin, @NotNull D delegate, @NotNull PsiClass containingClass) {
super(manager, JavaLanguage.INSTANCE);
this.origin = origin;
this.delegate = delegate;
this.containingClass = containingClass;
}
@NotNull
@Override
public abstract KotlinLightField<T, D> copy();
@Override
public void setInitializer(@Nullable PsiExpression initializer) throws IncorrectOperationException {
throw new IncorrectOperationException("Not supported");
}
@NotNull
@Override
public SearchScope getUseScope() {
return delegate.getUseScope();
}
@Override
public String getName() {
return delegate.getName();
}
@NotNull
@Override
public PsiIdentifier getNameIdentifier() {
return delegate.getNameIdentifier();
}
@Override
public PsiDocComment getDocComment() {
return delegate.getDocComment();
}
@Override
public boolean isDeprecated() {
return delegate.isDeprecated();
}
@Override
public PsiClass getContainingClass() {
return containingClass;
}
@NotNull
@Override
public PsiType getType() {
return delegate.getType();
}
@Override
public PsiTypeElement getTypeElement() {
return delegate.getTypeElement();
}
@Override
public PsiExpression getInitializer() {
return delegate.getInitializer();
}
@Override
public boolean hasInitializer() {
return delegate.hasInitializer();
}
@Override
public void normalizeDeclaration() throws IncorrectOperationException {
throw new IncorrectOperationException("Not supported");
}
@Override
public Object computeConstantValue() {
return delegate.computeConstantValue();
}
@Override
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
throw new IncorrectOperationException("Not supported");
}
@Override
public PsiModifierList getModifierList() {
return delegate.getModifierList();
}
@Override
public boolean hasModifierProperty(@NonNls @NotNull String name) {
return delegate.hasModifierProperty(name);
}
@Override
public String getText() {
return delegate.getText();
}
@Override
public TextRange getTextRange() {
return new TextRange(-1, -1);
}
@Override
public boolean isValid() {
return containingClass.isValid();
}
@Override
public String toString() {
return "PsiField:" + getName();
}
@NotNull
@Override
public T getOrigin() {
return origin;
}
@NotNull
@Override
public D getDelegate() {
return delegate;
}
@NotNull
@Override
public PsiElement getNavigationElement() {
return getOrigin();
}
@NotNull
@Override
public Language getLanguage() {
return JetLanguage.INSTANCE;
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.*
import org.jetbrains.jet.lang.psi.JetDeclaration
class KotlinLightFieldForDeclaration(
manager: PsiManager,
origin: JetDeclaration,
field: PsiField,
containingClass: PsiClass
) : KotlinLightField<JetDeclaration, PsiField>(manager, origin, field, containingClass) {
override fun copy() = KotlinLightFieldForDeclaration(getManager()!!, getOrigin(), getDelegate(), getContainingClass()!!)
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.PsiMethod
import org.jetbrains.jet.lang.psi.JetDeclaration
public trait KotlinLightMethod: PsiMethod, KotlinLightElement<JetDeclaration, PsiMethod>
@@ -0,0 +1,128 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.impl.light.LightMethod
import com.intellij.psi.*
import org.jetbrains.jet.lang.psi.JetDeclaration
import org.jetbrains.jet.plugin.JetLanguage
import kotlin.properties.Delegates
import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValue
import org.jetbrains.jet.lang.psi.JetPropertyAccessor
import org.jetbrains.jet.lang.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.jet.lang.psi.JetProperty
import org.jetbrains.jet.lang.psi.JetClassOrObject
import com.intellij.psi.impl.light.LightTypeParameterListBuilder
import com.intellij.psi.search.SearchScope
import com.intellij.lang.Language
import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.psi.util.MethodSignature
import com.intellij.psi.util.MethodSignatureBackedByPsiMethod
open public class KotlinLightMethodForDeclaration(
manager: PsiManager,
override val delegate: PsiMethod,
override val origin: JetDeclaration,
containingClass: PsiClass
): LightMethod(manager, delegate, containingClass), KotlinLightMethod {
private val paramsList: CachedValue<PsiParameterList> by Delegates.blockingLazy {
val cacheManager = CachedValuesManager.getManager(delegate.getProject())
cacheManager.createCachedValue<PsiParameterList>({
val parameterBuilder = LightParameterListBuilder(getManager(), JetLanguage.INSTANCE, this)
for ((index, parameter) in delegate.getParameterList().getParameters().withIndices()) {
parameterBuilder.addParameter(KotlinLightParameter(parameter, index, this))
}
CachedValueProvider.Result.create(parameterBuilder, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
}, false)
}
private val typeParamsList: CachedValue<PsiTypeParameterList> by Delegates.blockingLazy {
val cacheManager = CachedValuesManager.getManager(delegate.getProject())
cacheManager.createCachedValue<PsiTypeParameterList>({
val list = if (origin is JetClassOrObject) {
KotlinLightTypeParameterListBuilder(getManager())
}
else {
LightClassUtil.buildLightTypeParameterList(this@KotlinLightMethodForDeclaration, origin)
}
CachedValueProvider.Result.create(list, PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT)
}, false)
}
override fun getNavigationElement() : PsiElement = origin
override fun getOriginalElement() : PsiElement = origin
override fun getParent(): PsiElement? = getContainingClass()
override fun setName(name: String): PsiElement? {
(origin as PsiNamedElement).setName(name)
return this
}
public override fun delete() {
if (origin.isValid()) {
origin.delete()
}
}
override fun isEquivalentTo(another: PsiElement?): Boolean {
if (another is KotlinLightMethod && origin == another.origin) {
return true
}
return super<LightMethod>.isEquivalentTo(another)
}
override fun getParameterList(): PsiParameterList = paramsList.getValue()!!
override fun getTypeParameterList(): PsiTypeParameterList? = typeParamsList.getValue()
override fun getTypeParameters(): Array<PsiTypeParameter> =
getTypeParameterList()?.let { it.getTypeParameters() } ?: PsiTypeParameter.EMPTY_ARRAY
override fun getSignature(substitutor: PsiSubstitutor): MethodSignature {
if (substitutor == PsiSubstitutor.EMPTY) {
return delegate.getSignature(substitutor)
}
return MethodSignatureBackedByPsiMethod.create(this, substitutor)
}
override fun copy(): PsiElement {
return KotlinLightMethodForDeclaration(getManager()!!, delegate, origin.copy() as JetDeclaration, getContainingClass()!!)
}
override fun getUseScope(): SearchScope = origin.getUseScope()
override fun getLanguage(): Language = JetLanguage.INSTANCE
override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement): Boolean {
return getTypeParameters().all { processor.execute(it, state) }
}
override fun equals(other: Any?): Boolean =
other is KotlinLightMethodForDeclaration &&
getName() == other.getName() &&
origin == other.origin &&
getContainingClass() == other.getContainingClass()
override fun hashCode(): Int = (getName().hashCode() * 31 + origin.hashCode()) * 31 + getContainingClass()!!.hashCode()
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.PsiManager
import com.intellij.psi.PsiMethod
import org.jetbrains.jet.lang.psi.JetDeclaration
import com.intellij.psi.PsiClass
import org.jetbrains.jet.asJava.KotlinLightMethodForTraitFakeOverride
import com.intellij.psi.PsiElement
public class KotlinLightMethodForTraitFakeOverride(manager: PsiManager,
override val delegate: PsiMethod,
override val origin: JetDeclaration,
containingClass: PsiClass) :
KotlinLightMethodForDeclaration(manager, delegate, origin, containingClass) {
override fun copy(): PsiElement {
return KotlinLightMethodForTraitFakeOverride(getManager()!!, delegate, origin.copy() as JetDeclaration, getContainingClass()!!)
}
}
@@ -0,0 +1,58 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiManager;
import com.intellij.psi.impl.light.LightModifierList;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.plugin.JetLanguage;
public abstract class KotlinLightModifierList extends LightModifierList {
public KotlinLightModifierList(PsiManager psiManager, @NotNull String[] modifiers) {
super(psiManager, JetLanguage.INSTANCE, modifiers);
}
public abstract PsiAnnotationOwner getDelegate();
@Override
@NotNull
public PsiAnnotation[] getAnnotations() {
return getDelegate().getAnnotations();
}
@Override
@NotNull
public PsiAnnotation[] getApplicableAnnotations() {
return getDelegate().getApplicableAnnotations();
}
@Override
@Nullable
public PsiAnnotation findAnnotation(@NotNull @NonNls String qualifiedName) {
return getDelegate().findAnnotation(qualifiedName);
}
@Override
@NotNull
public PsiAnnotation addAnnotation(@NotNull @NonNls String qualifiedName) {
return getDelegate().addAnnotation(qualifiedName);
}
}
@@ -0,0 +1,108 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiModifierList;
import com.intellij.psi.PsiParameter;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
import org.jetbrains.jet.plugin.JetLanguage;
import java.util.List;
public class KotlinLightParameter extends LightParameter implements KotlinLightElement<JetParameter, PsiParameter> {
private static String getName(PsiParameter delegate, int index) {
String name = delegate.getName();
return name != null ? name : "p" + index;
}
private final PsiModifierList modifierList;
private final PsiParameter delegate;
private final int index;
private final KotlinLightMethod method;
public KotlinLightParameter(final PsiParameter delegate, int index, KotlinLightMethod method) {
super(getName(delegate, index), delegate.getType(), method, JetLanguage.INSTANCE);
this.delegate = delegate;
this.index = index;
this.method = method;
this.modifierList = new KotlinLightModifierList(method.getManager(), ArrayUtil.EMPTY_STRING_ARRAY) {
@Override
public PsiAnnotationOwner getDelegate() {
return delegate.getModifierList();
}
};
}
@NotNull
@Override
public PsiModifierList getModifierList() {
return modifierList;
}
@NotNull
@Override
public PsiParameter getDelegate() {
return delegate;
}
@Nullable
@Override
public JetParameter getOrigin() {
JetDeclaration declaration = method.getOrigin();
if (declaration == null) return null;
int jetIndex = PsiUtilPackage.isExtensionDeclaration(declaration) ? index - 1 : index;
if (jetIndex < 0) return null;
if (declaration instanceof JetNamedFunction) {
List<JetParameter> paramList = ((JetNamedFunction) declaration).getValueParameters();
return jetIndex < paramList.size() ? paramList.get(jetIndex) : null;
}
if (declaration instanceof JetClass) {
List<JetParameter> paramList = ((JetClass) declaration).getPrimaryConstructorParameters();
return jetIndex < paramList.size() ? paramList.get(jetIndex) : null;
}
if (jetIndex != 0) return null;
JetPropertyAccessor setter = null;
if (declaration instanceof JetPropertyAccessor) {
JetPropertyAccessor accessor = (JetPropertyAccessor) declaration;
setter = accessor.isSetter() ? accessor : null;
}
else if (declaration instanceof JetProperty) {
setter = ((JetProperty) declaration).getSetter();
}
return setter != null ? setter.getParameter() : null;
}
@NotNull
@Override
public Language getLanguage() {
return JetLanguage.INSTANCE;
}
}
@@ -0,0 +1,143 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.AbstractLightClass;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetTypeParameter;
import org.jetbrains.jet.lang.psi.JetTypeParameterListOwner;
import org.jetbrains.jet.plugin.JetLanguage;
public class KotlinLightTypeParameter
extends AbstractLightClass implements PsiTypeParameter, KotlinLightElement<JetTypeParameter, PsiTypeParameter> {
private final PsiTypeParameterListOwner owner;
private final int index;
private final String name;
protected KotlinLightTypeParameter(
@NotNull PsiTypeParameterListOwner owner,
int index,
@NotNull String name) {
super(owner.getManager(), JetLanguage.INSTANCE);
this.owner = owner;
this.index = index;
this.name = name;
}
@NotNull
@Override
public PsiTypeParameter getDelegate() {
return getOwnerDelegate().getTypeParameters()[index];
}
@NotNull
@Override
public JetTypeParameter getOrigin() {
JetTypeParameterListOwner jetOwner = (JetTypeParameterListOwner) AsJavaPackage.getUnwrapped(owner);
assert (jetOwner != null) : "Invalid type parameter owner: " + owner;
return jetOwner.getTypeParameters().get(index);
}
@NotNull
private PsiTypeParameterListOwner getOwnerDelegate() {
if (owner instanceof KotlinLightClass) return ((KotlinLightClass) owner).getDelegate();
if (owner instanceof KotlinLightMethod) return ((KotlinLightMethod) owner).getDelegate();
return owner;
}
@NotNull
@Override
public PsiElement copy() {
return new KotlinLightTypeParameter(owner, index, name);
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor) visitor).visitTypeParameter(this);
}
else {
super.accept(visitor);
}
}
@Nullable
@Override
public String getName() {
return name;
}
@Override
public PsiTypeParameterListOwner getOwner() {
return owner;
}
@Override
public int getIndex() {
return index;
}
@NotNull
@Override
public PsiAnnotation[] getAnnotations() {
return getDelegate().getAnnotations();
}
@NotNull
@Override
public PsiAnnotation[] getApplicableAnnotations() {
return getDelegate().getApplicableAnnotations();
}
@Override
public PsiAnnotation findAnnotation(@NotNull String qualifiedName) {
return getDelegate().findAnnotation(qualifiedName);
}
@NotNull
@Override
public PsiAnnotation addAnnotation(@NotNull String qualifiedName) {
return getDelegate().addAnnotation(qualifiedName);
}
@Override
public String toString() {
return "KotlinLightTypeParameter:" + getName();
}
@NotNull
@Override
public PsiElement getNavigationElement() {
return getOrigin();
}
@NotNull
@Override
public Language getLanguage() {
return JetLanguage.INSTANCE;
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
return obj instanceof KotlinLightTypeParameter && getOrigin().equals(((KotlinLightTypeParameter) obj).getOrigin());
}
}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.PsiManager
import org.jetbrains.jet.plugin.JetLanguage
import com.intellij.psi.impl.light.LightTypeParameterListBuilder
import com.intellij.psi.scope.PsiScopeProcessor
import com.intellij.psi.ResolveState
import com.intellij.psi.PsiElement
public class KotlinLightTypeParameterListBuilder(manager: PsiManager): LightTypeParameterListBuilder(manager, JetLanguage.INSTANCE) {
override fun processDeclarations(processor: PsiScopeProcessor, state: ResolveState, lastParent: PsiElement?, place: PsiElement): Boolean {
return getTypeParameters().all { processor.execute(it, state) }
}
}
@@ -0,0 +1,201 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.navigation.ItemPresentation;
import com.intellij.navigation.ItemPresentationProviders;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.psi.impl.light.AbstractLightClass;
import com.intellij.psi.impl.light.LightField;
import com.intellij.psi.impl.light.LightMethod;
import com.intellij.psi.impl.source.ClassInnerStuffCache;
import com.intellij.psi.impl.source.PsiExtensibleClass;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.plugin.JetLanguage;
import java.util.List;
public abstract class KotlinWrappingLightClass extends AbstractLightClass implements KotlinLightClass, PsiExtensibleClass {
private final ClassInnerStuffCache myInnersCache = new ClassInnerStuffCache(this);
protected KotlinWrappingLightClass(PsiManager manager) {
super(manager, JetLanguage.INSTANCE);
}
@NotNull
@Override
public abstract PsiClass getDelegate();
@Override
@NotNull
public PsiField[] getFields() {
return myInnersCache.getFields();
}
@Override
@NotNull
public PsiMethod[] getMethods() {
return myInnersCache.getMethods();
}
@Override
@NotNull
public PsiMethod[] getConstructors() {
return myInnersCache.getConstructors();
}
@Override
@NotNull
public PsiClass[] getInnerClasses() {
return myInnersCache.getInnerClasses();
}
@Override
@NotNull
public PsiField[] getAllFields() {
return PsiClassImplUtil.getAllFields(this);
}
@Override
@NotNull
public PsiMethod[] getAllMethods() {
return PsiClassImplUtil.getAllMethods(this);
}
@Override
@NotNull
public PsiClass[] getAllInnerClasses() {
return PsiClassImplUtil.getAllInnerClasses(this);
}
@Override
public PsiField findFieldByName(String name, boolean checkBases) {
return myInnersCache.findFieldByName(name, checkBases);
}
@Override
@NotNull
public PsiMethod[] findMethodsByName(String name, boolean checkBases) {
return myInnersCache.findMethodsByName(name, checkBases);
}
@Override
public PsiClass findInnerClassByName(String name, boolean checkBases) {
return myInnersCache.findInnerClassByName(name, checkBases);
}
/**
* @see org.jetbrains.jet.codegen.binding.CodegenBinding#ENUM_ENTRY_CLASS_NEED_SUBCLASS
*/
@NotNull
@Override
public List<PsiField> getOwnFields() {
return ContainerUtil.map(getDelegate().getFields(), new Function<PsiField, PsiField>() {
@Override
public PsiField fun(PsiField field) {
JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(field);
if (declaration instanceof JetEnumEntry) {
assert field instanceof PsiEnumConstant : "Field delegate should be an enum constant (" + field.getName() + "):\n" +
JetPsiUtil.getElementTextWithContext(declaration);
JetEnumEntry enumEntry = (JetEnumEntry) declaration;
PsiEnumConstant enumConstant = (PsiEnumConstant) field;
FqName enumConstantFqName = new FqName(getFqName().asString() + "." + enumEntry.getName());
KotlinLightClassForEnumEntry initializingClass =
enumEntry.getDeclarations().isEmpty()
? null
: new KotlinLightClassForEnumEntry(myManager, enumConstantFqName, enumEntry, enumConstant);
return new KotlinLightEnumConstant(myManager, enumEntry, enumConstant, KotlinWrappingLightClass.this, initializingClass);
}
if (declaration != null) {
return new KotlinLightFieldForDeclaration(myManager, declaration, field, KotlinWrappingLightClass.this);
}
return new LightField(myManager, field, KotlinWrappingLightClass.this);
}
});
}
@NotNull
@Override
public List<PsiMethod> getOwnMethods() {
return KotlinPackage.map(getDelegate().getMethods(), new Function1<PsiMethod, PsiMethod>() {
@Override
public PsiMethod invoke(PsiMethod method) {
JetDeclaration declaration = ClsWrapperStubPsiFactory.getOriginalDeclaration(method);
if (declaration != null) {
return !isTraitFakeOverride(declaration) ?
new KotlinLightMethodForDeclaration(myManager, method, declaration, KotlinWrappingLightClass.this) :
new KotlinLightMethodForTraitFakeOverride(myManager, method, declaration, KotlinWrappingLightClass.this);
}
return new LightMethod(myManager, method, KotlinWrappingLightClass.this);
}
});
}
@Override
public boolean processDeclarations(
@NotNull PsiScopeProcessor processor, @NotNull ResolveState state, PsiElement lastParent, @NotNull PsiElement place
) {
if (isEnum()) {
if (!PsiClassImplUtil.processDeclarationsInEnum(processor, state, myInnersCache)) return false;
}
return super.processDeclarations(processor, state, lastParent, place);
}
@Override
public String getText() {
JetClassOrObject origin = getOrigin();
return origin == null ? null : origin.getText();
}
@NotNull
@Override
public Language getLanguage() {
return JetLanguage.INSTANCE;
}
private boolean isTraitFakeOverride(@NotNull JetDeclaration originMethodDeclaration) {
if (!(originMethodDeclaration instanceof JetNamedFunction ||
originMethodDeclaration instanceof JetPropertyAccessor ||
originMethodDeclaration instanceof JetProperty)) {
return false;
}
JetClassOrObject parentOfMethodOrigin = PsiTreeUtil.getParentOfType(originMethodDeclaration, JetClassOrObject.class);
JetClassOrObject thisClassDeclaration = getOrigin();
// Method was generated from declaration in some other trait
return (parentOfMethodOrigin != null && thisClassDeclaration != parentOfMethodOrigin && JetPsiUtil.isTrait(parentOfMethodOrigin));
}
@Override
public ItemPresentation getPresentation() {
return ItemPresentationProviders.getItemPresentation(this);
}
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ModuleDescriptor;
import org.jetbrains.jet.lang.resolve.BindingContext;
public class LightClassConstructionContext {
private final BindingContext bindingContext;
private final ModuleDescriptor module;
public LightClassConstructionContext(@NotNull BindingContext bindingContext, @NotNull ModuleDescriptor module) {
this.bindingContext = bindingContext;
this.module = module;
}
@NotNull
public BindingContext getBindingContext() {
return bindingContext;
}
@NotNull
public ModuleDescriptor getModule() {
return module;
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.JetClassOrObject;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.Collection;
public abstract class LightClassGenerationSupport {
@NotNull
public static LightClassGenerationSupport getInstance(@NotNull Project project) {
return ServiceManager.getService(project, LightClassGenerationSupport.class);
}
@NotNull
public abstract LightClassConstructionContext getContextForPackage(@NotNull Collection<JetFile> files);
@NotNull
public abstract LightClassConstructionContext getContextForClassOrObject(@NotNull JetClassOrObject classOrObject);
@NotNull
public abstract Collection<JetClassOrObject> findClassOrObjectDeclarations(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope);
/*
* Finds files whose package declaration is exactly {@code fqName}. For example, if a file declares
* package a.b.c
* it will not be returned for fqName "a.b"
*
* If the resulting collection is empty, it means that this package has not other declarations than sub-packages
*/
@NotNull
public abstract Collection<JetFile> findFilesForPackage(@NotNull FqName fqName, @NotNull GlobalSearchScope searchScope);
// Returns only immediately declared classes/objects, package classes are not included (they have no declarations)
@NotNull
public abstract Collection<JetClassOrObject> findClassOrObjectDeclarationsInPackage(
@NotNull FqName packageFqName,
@NotNull GlobalSearchScope searchScope
);
public abstract boolean packageExists(@NotNull FqName fqName, @NotNull GlobalSearchScope scope);
@NotNull
public abstract Collection<FqName> getSubPackages(@NotNull FqName fqn, @NotNull GlobalSearchScope scope);
@Nullable
public abstract PsiClass getPsiClass(@NotNull JetClassOrObject classOrObject);
@NotNull
public abstract Collection<PsiClass> getPackageClasses(@NotNull FqName packageFqName, @NotNull GlobalSearchScope scope);
}
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.impl.java.stubs.PsiJavaFileStub
import org.jetbrains.jet.lang.descriptors.ClassDescriptor
import org.jetbrains.jet.lang.psi.JetClassOrObject
import org.jetbrains.jet.lang.resolve.diagnostics.Diagnostics
import org.jetbrains.jet.lang.resolve.name.FqName
trait LightClassData
trait WithFileStubAndExtraDiagnostics {
val javaFileStub: PsiJavaFileStub
val extraDiagnostics: Diagnostics
}
trait LightClassDataForKotlinClass: LightClassData {
val classOrObject: JetClassOrObject
val descriptor: ClassDescriptor?
val jvmQualifiedName: FqName
}
data class KotlinPackageLightClassData(
override val javaFileStub: PsiJavaFileStub,
override val extraDiagnostics: Diagnostics
): LightClassData, WithFileStubAndExtraDiagnostics
data class InnerKotlinClassLightClassData(
override val jvmQualifiedName: FqName,
override val classOrObject: JetClassOrObject,
override val descriptor: ClassDescriptor?
): LightClassDataForKotlinClass
data class OutermostKotlinClassLightClassData(
override val javaFileStub: PsiJavaFileStub,
override val extraDiagnostics: Diagnostics,
override val jvmQualifiedName: FqName,
override val classOrObject: JetClassOrObject,
override val descriptor: ClassDescriptor?,
val allInnerClasses: Map<JetClassOrObject, InnerKotlinClassLightClassData>
): LightClassDataForKotlinClass, WithFileStubAndExtraDiagnostics
@@ -0,0 +1,354 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.light.LightTypeParameterListBuilder;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.stubs.PsiFileStub;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.PathUtil;
import com.intellij.util.SmartList;
import kotlin.Function1;
import kotlin.KotlinPackage;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
import org.jetbrains.jet.utils.KotlinVfsUtil;
import org.jetbrains.jet.utils.UtilsPackage;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
public class LightClassUtil {
private static final Logger LOG = Logger.getInstance(LightClassUtil.class);
public static final File BUILT_INS_SRC_DIR = new File("core/builtins/native", KotlinBuiltIns.BUILT_INS_PACKAGE_NAME.asString());
private static final class BuiltinsDirUrlHolder {
private static final URL BUILT_INS_DIR_URL = computeBuiltInsDir();
}
/**
* Checks whether the given file is loaded from the location where Kotlin's built-in classes are defined.
* As of today, this is core/builtins/native/kotlin directory and files such as Any.kt, Nothing.kt etc.
*
* Used to skip JetLightClass creation for built-ins, because built-in classes have no Java counterparts
*/
public static boolean belongsToKotlinBuiltIns(@NotNull JetFile file) {
VirtualFile virtualFile = file.getVirtualFile();
if (virtualFile != null) {
VirtualFile parent = virtualFile.getParent();
if (parent != null) {
try {
String jetVfsPathUrl = KotlinVfsUtil.convertFromUrl(getBuiltInsDirUrl());
String fileDirVfsUrl = parent.getUrl();
if (jetVfsPathUrl.equals(fileDirVfsUrl)) {
return true;
}
}
catch (MalformedURLException e) {
LOG.error(e);
}
}
}
// We deliberately return false on error: who knows what weird URLs we might come across out there
// it would be a pity if no light classes would be created in such cases
return false;
}
@NotNull
public static URL getBuiltInsDirUrl() {
return BuiltinsDirUrlHolder.BUILT_INS_DIR_URL;
}
@NotNull
private static URL computeBuiltInsDir() {
String builtInFilePath = "/" + KotlinBuiltIns.BUILT_INS_PACKAGE_NAME + "/Library.kt";
URL url = KotlinBuiltIns.class.getResource(builtInFilePath);
if (url == null) {
if (ApplicationManager.getApplication().isUnitTestMode()) {
// HACK: Temp code. Get built-in files from the sources when running from test.
try {
return new URL(StandardFileSystems.FILE_PROTOCOL, "",
FileUtil.toSystemIndependentName(BUILT_INS_SRC_DIR.getAbsolutePath()));
}
catch (MalformedURLException e) {
throw UtilsPackage.rethrow(e);
}
}
throw new IllegalStateException("Built-ins file wasn't found at url: " + builtInFilePath);
}
try {
return new URL(url.getProtocol(), url.getHost(), PathUtil.getParentPath(url.getFile()));
}
catch (MalformedURLException e) {
throw new AssertionError(e);
}
}
@Nullable
/*package*/ static PsiClass findClass(@NotNull FqName fqn, @NotNull StubElement<?> stub) {
if (stub instanceof PsiClassStub && Comparing.equal(fqn.asString(), ((PsiClassStub) stub).getQualifiedName())) {
return (PsiClass) stub.getPsi();
}
if (stub instanceof PsiClassStub || stub instanceof PsiFileStub) {
for (StubElement child : stub.getChildrenStubs()) {
PsiClass answer = findClass(fqn, child);
if (answer != null) return answer;
}
}
return null;
}
@Nullable
public static PsiClass getPsiClass(@Nullable JetClassOrObject classOrObject) {
if (classOrObject == null) return null;
return LightClassGenerationSupport.getInstance(classOrObject.getProject()).getPsiClass(classOrObject);
}
@Nullable
public static PsiMethod getLightClassAccessorMethod(@NotNull JetPropertyAccessor accessor) {
return getPsiMethodWrapper(accessor);
}
@NotNull
public static PropertyAccessorsPsiMethods getLightClassPropertyMethods(@NotNull JetProperty property) {
JetPropertyAccessor getter = property.getGetter();
JetPropertyAccessor setter = property.getSetter();
PsiMethod getterWrapper = getter != null ? getLightClassAccessorMethod(getter) : null;
PsiMethod setterWrapper = setter != null ? getLightClassAccessorMethod(setter) : null;
return extractPropertyAccessors(property, getterWrapper, setterWrapper);
}
@NotNull
public static PropertyAccessorsPsiMethods getLightClassPropertyMethods(@NotNull JetParameter parameter) {
return extractPropertyAccessors(parameter, null, null);
}
@Nullable
public static PsiMethod getLightClassMethod(@NotNull JetNamedFunction function) {
return getPsiMethodWrapper(function);
}
@Nullable
private static PsiMethod getPsiMethodWrapper(@NotNull JetDeclaration declaration) {
List<PsiMethod> wrappers = getPsiMethodWrappers(declaration, false);
return !wrappers.isEmpty() ? wrappers.get(0) : null;
}
@NotNull
private static List<PsiMethod> getPsiMethodWrappers(@NotNull JetDeclaration declaration, boolean collectAll) {
PsiClass psiClass = getWrappingClass(declaration);
if (psiClass == null) {
return Collections.emptyList();
}
List<PsiMethod> methods = new SmartList<PsiMethod>();
for (PsiMethod method : psiClass.getMethods()) {
try {
if (method instanceof KotlinLightMethod && ((KotlinLightMethod) method).getOrigin() == declaration) {
methods.add(method);
if (!collectAll) {
return methods;
}
}
}
catch (ProcessCanceledException e) {
throw e;
}
catch (Throwable e) {
throw new IllegalStateException(
"Error while wrapping declaration " + declaration.getName() +
"Context\n:" +
String.format("=== In file ===\n" +
"%s\n" +
"=== On element ===\n" +
"%s\n" +
"=== WrappedElement ===\n" +
"%s\n",
declaration.getContainingFile().getText(),
declaration.getText(),
method.toString()),
e
);
}
}
return methods;
}
@Nullable
private static PsiClass getWrappingClass(@NotNull JetDeclaration declaration) {
if (declaration instanceof JetParameter) {
JetClass constructorClass = JetPsiUtil.getClassIfParameterIsProperty((JetParameter) declaration);
if (constructorClass != null) {
return getPsiClass(constructorClass);
}
}
if (declaration instanceof JetPropertyAccessor) {
PsiElement propertyParent = declaration.getParent();
assert propertyParent instanceof JetProperty : "JetProperty is expected to be parent of accessor";
declaration = (JetProperty) propertyParent;
}
//noinspection unchecked
if (PsiTreeUtil.getParentOfType(declaration, JetFunction.class, JetProperty.class) != null) {
// Can't get wrappers for internal declarations. Their classes are not generated during calcStub
// with ClassBuilderMode.LIGHT_CLASSES mode, and this produces "Class not found exception" in getDelegate()
return null;
}
PsiElement parent = declaration.getParent();
if (parent instanceof JetFile) {
// top-level declaration
FqName fqName = PackageClassUtils.getPackageClassFqName(((JetFile) parent).getPackageFqName());
Project project = declaration.getProject();
return JavaElementFinder.getInstance(project).findClass(fqName.asString(), GlobalSearchScope.allScope(project));
}
else if (parent instanceof JetClassBody) {
assert parent.getParent() instanceof JetClassOrObject;
return getPsiClass((JetClassOrObject) parent.getParent());
}
return null;
}
@NotNull
private static PropertyAccessorsPsiMethods extractPropertyAccessors(
@NotNull JetDeclaration jetDeclaration,
@Nullable PsiMethod specialGetter, @Nullable PsiMethod specialSetter
) {
PsiMethod getterWrapper = specialGetter;
PsiMethod setterWrapper = specialSetter;
if (getterWrapper == null || setterWrapper == null) {
// If some getter or setter isn't found yet try to get it from wrappers for general declaration
List<PsiMethod> wrappers = KotlinPackage.filter(
getPsiMethodWrappers(jetDeclaration, true),
new Function1<PsiMethod, Boolean>() {
@Override
public Boolean invoke(PsiMethod method) {
return JvmAbi.isAccessorName(method.getName());
}
}
);
assert wrappers.size() <= 2 : "Maximum two wrappers are expected to be generated for declaration: " + jetDeclaration.getText();
for (PsiMethod wrapper : wrappers) {
if (wrapper.getName().startsWith(JvmAbi.SETTER_PREFIX)) {
assert setterWrapper == null : String.format(
"Setter accessor isn't expected to be reassigned (old: %s, new: %s)", setterWrapper, wrapper);
setterWrapper = wrapper;
}
else {
assert getterWrapper == null : String.format(
"Getter accessor isn't expected to be reassigned (old: %s, new: %s)", getterWrapper, wrapper);
getterWrapper = wrapper;
}
}
}
return new PropertyAccessorsPsiMethods(getterWrapper, setterWrapper);
}
@NotNull
public static PsiTypeParameterList buildLightTypeParameterList(
PsiTypeParameterListOwner owner,
JetDeclaration declaration) {
LightTypeParameterListBuilder builder = new KotlinLightTypeParameterListBuilder(owner.getManager());
if (declaration instanceof JetTypeParameterListOwner) {
JetTypeParameterListOwner typeParameterListOwner = (JetTypeParameterListOwner) declaration;
List<JetTypeParameter> parameters = typeParameterListOwner.getTypeParameters();
for (int i = 0; i < parameters.size(); i++) {
JetTypeParameter jetTypeParameter = parameters.get(i);
String name = jetTypeParameter.getName();
String safeName = name == null ? "__no_name__" : name;
builder.addParameter(new KotlinLightTypeParameter(owner, i, safeName));
}
}
return builder;
}
public static class PropertyAccessorsPsiMethods implements Iterable<PsiMethod> {
private final PsiMethod getter;
private final PsiMethod setter;
private final Collection<PsiMethod> accessors = new ArrayList<PsiMethod>(2);
PropertyAccessorsPsiMethods(@Nullable PsiMethod getter, @Nullable PsiMethod setter) {
this.getter = getter;
if (getter != null) {
accessors.add(getter);
}
this.setter = setter;
if (setter != null) {
accessors.add(setter);
}
}
@Nullable
public PsiMethod getGetter() {
return getter;
}
@Nullable
public PsiMethod getSetter() {
return setter;
}
@NotNull
@Override
public Iterator<PsiMethod> iterator() {
return accessors.iterator();
}
}
private LightClassUtil() {
}
}
@@ -0,0 +1,69 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
// Based on com.intellij.psi.impl.light.LightParameter
public class LightParameter extends LightVariableBuilder implements PsiParameter {
public static final LightParameter[] EMPTY_ARRAY = new LightParameter[0];
private final String myName;
private final PsiElement myDeclarationScope;
private final boolean myVarArgs;
public LightParameter(@NotNull String name, @NotNull PsiType type, PsiElement declarationScope, Language language) {
this(name, type, declarationScope, language, type instanceof PsiEllipsisType);
}
public LightParameter(@NotNull String name, @NotNull PsiType type, PsiElement declarationScope, Language language, boolean isVarArgs) {
super(declarationScope.getManager(), name, type, language);
myName = name;
myDeclarationScope = declarationScope;
myVarArgs = isVarArgs;
}
@NotNull
@Override
public PsiElement getDeclarationScope() {
return myDeclarationScope;
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor)visitor).visitParameter(this);
}
}
public String toString() {
return "Light Parameter";
}
@Override
public boolean isVarArgs() {
return myVarArgs;
}
@Override
@NotNull
public String getName() {
return myName;
}
}
@@ -0,0 +1,84 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.psi.*;
import com.intellij.psi.impl.light.LightElement;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
// Copy of com.intellij.psi.impl.light.LightParameterListBuilder
public class LightParameterListBuilder extends LightElement implements PsiParameterList {
private final List<PsiParameter> myParameters = new ArrayList<PsiParameter>();
private final KotlinLightMethod parent;
private PsiParameter[] myCachedParameters;
public LightParameterListBuilder(PsiManager manager, Language language, KotlinLightMethod parent) {
super(manager, language);
this.parent = parent;
}
public void addParameter(PsiParameter parameter) {
myParameters.add(parameter);
myCachedParameters = null;
}
@Override
public KotlinLightMethod getParent() {
return parent;
}
@Override
public String toString() {
return "Light parameter lsit";
}
@NotNull
@Override
public PsiParameter[] getParameters() {
if (myCachedParameters == null) {
if (myParameters.isEmpty()) {
myCachedParameters = PsiParameter.EMPTY_ARRAY;
}
else {
myCachedParameters = myParameters.toArray(new PsiParameter[myParameters.size()]);
}
}
return myCachedParameters;
}
@Override
public int getParameterIndex(PsiParameter parameter) {
return myParameters.indexOf(parameter);
}
@Override
public int getParametersCount() {
return myParameters.size();
}
@Override
public void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof JavaElementVisitor) {
((JavaElementVisitor) visitor).visitParameterList(this);
}
}
}
@@ -0,0 +1,118 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.lang.Language;
import com.intellij.navigation.NavigationItem;
import com.intellij.psi.*;
import com.intellij.psi.impl.ElementPresentationUtil;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.impl.light.LightModifierList;
import com.intellij.ui.RowIcon;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PlatformIcons;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
// Based on com.intellij.psi.impl.light.LightVariableBuilder
public class LightVariableBuilder extends LightElement implements PsiVariable, NavigationItem {
private final String myName;
private final PsiType myType;
private final LightModifierList myModifierList;
public LightVariableBuilder(PsiManager manager, @NotNull String name, @NotNull PsiType type, Language language) {
super(manager, language);
myName = name;
myType = type;
myModifierList = new LightModifierList(manager);
}
@Override
public String toString() {
return "LightVariableBuilder:" + getName();
}
@NotNull
@Override
public PsiType getType() {
return myType;
}
@Override
@NotNull
public PsiModifierList getModifierList() {
return myModifierList;
}
@Override
public boolean hasModifierProperty(@NonNls @NotNull String name) {
return myModifierList.hasModifierProperty(name);
}
@NotNull
@Override
public String getName() {
return myName;
}
@Override
public PsiTypeElement getTypeElement() {
return null;
}
@Override
public PsiExpression getInitializer() {
return null;
}
@Override
public boolean hasInitializer() {
return false;
}
@Override
public void normalizeDeclaration() throws IncorrectOperationException {
}
@Override
public Object computeConstantValue() {
return null;
}
@Override
public PsiIdentifier getNameIdentifier() {
return null;
}
@Override
public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
throw new UnsupportedOperationException("setName is not implemented yet in org.jetbrains.jet.asJava.light.LightVariableBuilder");
}
@Override
protected boolean isVisibilitySupported() {
return true;
}
@Override
public Icon getElementIcon(int flags) {
RowIcon baseIcon = ElementPresentationUtil.createLayeredIcon(PlatformIcons.VARIABLE_ICON, this, false);
return ElementPresentationUtil.addVisibilityIcon(this, flags, baseIcon);
}
}
@@ -0,0 +1,158 @@
/*
* Copyright 2010-2013 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.compiled.InnerClassSourceStrategy;
import com.intellij.psi.impl.compiled.StubBuildingVisitor;
import com.intellij.psi.stubs.StubBase;
import com.intellij.psi.stubs.StubElement;
import com.intellij.util.containers.Stack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOrigin;
import org.jetbrains.org.objectweb.asm.ClassVisitor;
import org.jetbrains.org.objectweb.asm.FieldVisitor;
import org.jetbrains.org.objectweb.asm.MethodVisitor;
import org.jetbrains.jet.codegen.AbstractClassBuilder;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.resolve.java.PackageClassUtils;
import org.jetbrains.jet.lang.resolve.name.FqName;
import java.util.List;
public class StubClassBuilder extends AbstractClassBuilder {
private static final InnerClassSourceStrategy<Object> EMPTY_STRATEGY = new InnerClassSourceStrategy<Object>() {
@Override
public Object findInnerClass(String s, Object o) {
return null;
}
@Override
public void accept(Object innerClass, StubBuildingVisitor<Object> visitor) {
throw new UnsupportedOperationException("Shall not be called!");
}
};
private final StubElement parent;
private StubBuildingVisitor v;
private final Stack<StubElement> parentStack;
private boolean isPackageClass = false;
public StubClassBuilder(@NotNull Stack<StubElement> parentStack) {
this.parentStack = parentStack;
this.parent = parentStack.peek();
}
@NotNull
@Override
public ClassVisitor getVisitor() {
assert v != null : "Called before class is defined";
return v;
}
@Override
public void defineClass(
PsiElement origin,
int version,
int access,
@NotNull String name,
@Nullable String signature,
@NotNull String superName,
@NotNull String[] interfaces
) {
assert v == null : "defineClass() called twice?";
v = new StubBuildingVisitor<Object>(null, EMPTY_STRATEGY, parent, access, null);
super.defineClass(origin, version, access, name, signature, superName, interfaces);
if (origin instanceof JetFile) {
FqName packageName = ((JetFile) origin).getPackageFqName();
String packageClassName = PackageClassUtils.getPackageClassName(packageName);
if (name.equals(packageClassName) || name.endsWith("/" + packageClassName)) {
isPackageClass = true;
}
}
if (!isPackageClass) {
parentStack.push(v.getResult());
}
((StubBase) v.getResult()).putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
}
@NotNull
@Override
public MethodVisitor newMethod(
@NotNull JvmDeclarationOrigin origin,
int access,
@NotNull String name,
@NotNull String desc,
@Nullable String signature,
@Nullable String[] exceptions
) {
MethodVisitor internalVisitor = super.newMethod(origin, access, name, desc, signature, exceptions);
if (internalVisitor != EMPTY_METHOD_VISITOR) {
// If stub for method generated
markLastChild(origin.getElement());
}
return internalVisitor;
}
@NotNull
@Override
public FieldVisitor newField(
@NotNull JvmDeclarationOrigin origin,
int access,
@NotNull String name,
@NotNull String desc,
@Nullable String signature,
@Nullable Object value
) {
FieldVisitor internalVisitor = super.newField(origin, access, name, desc, signature, value);
if (internalVisitor != EMPTY_FIELD_VISITOR) {
// If stub for field generated
markLastChild(origin.getElement());
}
return internalVisitor;
}
private void markLastChild(@Nullable PsiElement origin) {
List children = v.getResult().getChildrenStubs();
StubBase last = (StubBase) children.get(children.size() - 1);
PsiElement oldOrigin = last.getUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT);
if (oldOrigin != null) {
throw new IllegalStateException("Rewriting origin element: " + oldOrigin.getText() + " for stub " + last.toString());
}
last.putUserData(ClsWrapperStubPsiFactory.ORIGIN_ELEMENT, origin);
}
@Override
public void done() {
if (!isPackageClass) {
StubElement pop = parentStack.pop();
assert pop == v.getResult();
}
super.done();
}
}
@@ -0,0 +1,145 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.PsiElement
import org.jetbrains.jet.lang.resolve.diagnostics.Diagnostics
import org.jetbrains.jet.lang.psi.JetFile
import org.jetbrains.jet.lang.psi.JetClassBody
import org.jetbrains.jet.lang.psi.JetClassOrObject
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.jet.lang.psi.JetPropertyAccessor
import org.jetbrains.jet.lang.diagnostics.Diagnostic
import org.jetbrains.jet.lang.resolve.java.diagnostics.ErrorsJvm.*
import org.jetbrains.jet.lang.resolve.java.diagnostics.ConflictingJvmDeclarationsData
import org.jetbrains.jet.lang.resolve.java.diagnostics.JvmDeclarationOriginKind.*
import org.jetbrains.jet.lang.diagnostics.Errors.*
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory.*
import org.jetbrains.jet.lang.psi.JetParameter
import org.jetbrains.jet.lang.psi.JetClass
import org.jetbrains.jet.lang.diagnostics.DiagnosticFactory
public fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostics, moduleScope: GlobalSearchScope): Diagnostics? {
fun getDiagnosticsForPackage(file: JetFile): Diagnostics? {
val project = file.getProject()
val cache = KotlinLightClassForPackage.FileStubCache.getInstance(project)
return cache[file.getPackageFqName(), moduleScope].getValue()?.extraDiagnostics
}
fun getDiagnosticsForClass(jetClassOrObject: JetClassOrObject): Diagnostics {
return KotlinLightClassForExplicitDeclaration.getLightClassData(jetClassOrObject).extraDiagnostics
}
fun doGetDiagnostics(): Diagnostics? {
var parent = element.getParent()
if (element is JetPropertyAccessor) {
parent = parent?.getParent()
}
if (element is JetParameter && element.getValOrVarNode() != null) {
// property declared in constructor
val parentClass = parent?.getParent() as? JetClass
if (parentClass != null) {
return getDiagnosticsForClass(parentClass)
}
}
if (element is JetClassOrObject) {
return getDiagnosticsForClass(element)
}
when (parent) {
is JetFile -> {
return getDiagnosticsForPackage(parent as JetFile)
}
is JetClassBody -> {
val parentsParent = parent?.getParent()
if (parentsParent is JetClassOrObject) {
return getDiagnosticsForClass(parentsParent)
}
}
}
return null
}
val result = doGetDiagnostics()
if (result == null) return null
return FilteredJvmDiagnostics(result, otherDiagnostics)
}
class FilteredJvmDiagnostics(val jvmDiagnostics: Diagnostics, val otherDiagnostics: Diagnostics) : Diagnostics by jvmDiagnostics {
private fun alreadyReported(psiElement: PsiElement): Boolean {
val higherPriority = setOf<DiagnosticFactory<*>>(
CONFLICTING_OVERLOADS, REDECLARATION, NOTHING_TO_OVERRIDE, MANY_IMPL_MEMBER_NOT_IMPLEMENTED)
return otherDiagnostics.forElement(psiElement).any { it.getFactory() in higherPriority }
|| psiElement is JetPropertyAccessor && alreadyReported(psiElement.getParent()!!)
}
override fun forElement(psiElement: PsiElement): Collection<Diagnostic> {
val jvmDiagnosticFactories = setOf(CONFLICTING_JVM_DECLARATIONS, ACCIDENTAL_OVERRIDE)
fun Diagnostic.data() = cast(this, jvmDiagnosticFactories).getA()
val (conflicting, other) = jvmDiagnostics.forElement(psiElement).partition { it.getFactory() in jvmDiagnosticFactories }
if (alreadyReported(psiElement)) {
// CONFLICTING_OVERLOADS already reported, no need to duplicate it
return other
}
val filtered = arrayListOf<Diagnostic>()
conflicting.groupBy {
it.data().signature.name
}.forEach {
val diagnostics = it.getValue()
if (diagnostics.size() <= 1) {
filtered.addAll(diagnostics)
}
else {
filtered.addAll(
diagnostics.filter {
me ->
diagnostics.none {
other ->
me != other && (
// in case of implementation copied from a super trait there will be both diagnostics on the same signature
me.getFactory() == ACCIDENTAL_OVERRIDE && other.getFactory() == CONFLICTING_JVM_DECLARATIONS
// there are paris of corresponding signatures that frequently clash simultaneously: package facade & part, trait and trait-impl
|| other.data() higherThan me.data()
)
}
}
)
}
}
return filtered + other
}
override fun all(): Collection<Diagnostic> {
return jvmDiagnostics.all()
.map { it.getPsiElement() }
.toSet()
.flatMap { forElement(it) }
}
}
private fun ConflictingJvmDeclarationsData.higherThan(other: ConflictingJvmDeclarationsData): Boolean {
return when (other.classOrigin.originKind) {
PACKAGE_PART -> this.classOrigin.originKind == PACKAGE_FACADE
TRAIT_IMPL -> this.classOrigin.originKind != TRAIT_IMPL
else -> false
}
}
@@ -0,0 +1,103 @@
/*
* Copyright 2010-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.jet.asJava
import com.intellij.psi.*
import org.jetbrains.jet.lang.psi.*
import java.util.Collections
import org.jetbrains.jet.lang.psi.psiUtil.getNonStrictParentOfType
import java.util.ArrayList
import org.jetbrains.jet.lang.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.jet.utils.addToStdlib.singletonOrEmptyList
public fun JetClassOrObject.toLightClass(): KotlinLightClass? = LightClassUtil.getPsiClass(this) as KotlinLightClass?
public fun JetDeclaration.toLightElements(): List<PsiNamedElement> =
when (this) {
is JetClassOrObject -> Collections.singletonList(LightClassUtil.getPsiClass(this))
is JetNamedFunction -> Collections.singletonList(LightClassUtil.getLightClassMethod(this))
is JetProperty -> LightClassUtil.getLightClassPropertyMethods(this).toList()
is JetPropertyAccessor -> Collections.singletonList(LightClassUtil.getLightClassAccessorMethod(this))
is JetParameter -> ArrayList<PsiNamedElement>().let { elements ->
toPsiParameter()?.let { psiParameter -> elements.add(psiParameter) }
LightClassUtil.getLightClassPropertyMethods(this).toCollection(elements)
elements
}
is JetTypeParameter -> toPsiTypeParameters()
else -> listOf()
}
public fun PsiElement.toLightMethods(): List<PsiMethod> =
when (this) {
is JetNamedFunction -> LightClassUtil.getLightClassMethod(this).singletonOrEmptyList()
is JetProperty -> LightClassUtil.getLightClassPropertyMethods(this).toList()
is JetParameter -> LightClassUtil.getLightClassPropertyMethods(this).toList()
is JetPropertyAccessor -> LightClassUtil.getLightClassAccessorMethod(this).singletonOrEmptyList()
is JetClass -> Collections.singletonList(LightClassUtil.getPsiClass(this).getConstructors()[0])
is PsiMethod -> Collections.singletonList(this)
else -> listOf()
}
public fun PsiElement.getRepresentativeLightMethod(): PsiMethod? =
when (this) {
is JetNamedFunction -> LightClassUtil.getLightClassMethod(this)
is JetProperty -> LightClassUtil.getLightClassPropertyMethods(this).getGetter()
is JetParameter -> LightClassUtil.getLightClassPropertyMethods(this).getGetter()
is JetPropertyAccessor -> LightClassUtil.getLightClassAccessorMethod(this)
is PsiMethod -> this
else -> null
}
public fun JetParameter.toPsiParameter(): PsiParameter? {
val paramList = getNonStrictParentOfType<JetParameterList>()
if (paramList == null) return null
val paramIndex = paramList.getParameters().indexOf(this)
val owner = paramList.getParent()
val lightParamIndex = if (owner != null && owner.isExtensionDeclaration()) paramIndex + 1 else paramIndex
val method: PsiMethod? = when (owner) {
is JetNamedFunction -> LightClassUtil.getLightClassMethod(owner)
is JetPropertyAccessor -> LightClassUtil.getLightClassAccessorMethod(owner)
is JetClass -> LightClassUtil.getPsiClass(owner)?.getConstructors()?.let { constructors ->
if (constructors.isNotEmpty()) constructors[0] else null
}
else -> null
}
if (method == null) return null
return method.getParameterList().getParameters()[lightParamIndex]
}
public fun JetTypeParameter.toPsiTypeParameters(): List<PsiTypeParameter> {
val paramList = getNonStrictParentOfType<JetTypeParameterList>()
if (paramList == null) return listOf()
val paramIndex = paramList.getParameters().indexOf(this)
val jetDeclaration = paramList.getNonStrictParentOfType<JetDeclaration>() ?: return listOf()
val lightOwners = jetDeclaration.toLightElements()
return lightOwners.map { lightOwner -> (lightOwner as PsiTypeParameterListOwner).getTypeParameters()[paramIndex] }
}
// Returns original declaration if given PsiElement is a Kotlin light element, and element itself otherwise
public val PsiElement.unwrapped: PsiElement?
get() = if (this is KotlinLightElement<*, *>) origin else this
public val PsiElement.namedUnwrappedElement: PsiNamedElement?
get() = unwrapped?.getNonStrictParentOfType<PsiNamedElement>()