Move common jvm classes from :core:descriptors.jvm to :core:compiler.common.jvm

This commit is contained in:
Dmitriy Novozhilov
2020-09-01 17:59:45 +03:00
parent 9806a85cc1
commit 6906e0d82d
67 changed files with 347 additions and 321 deletions
@@ -1,23 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.asJava
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
interface KtLightClassMarker {
val originKind: LightClassOriginKind
}
@@ -1,15 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.asJava
import com.intellij.psi.PsiMethod
import com.intellij.psi.SyntheticElement
import org.jetbrains.kotlin.builtins.StandardNames
fun isSyntheticValuesOrValueOfMethod(method: PsiMethod): Boolean {
if (method !is SyntheticElement) return false
return StandardNames.ENUM_VALUE_OF.asString() == method.name || StandardNames.ENUM_VALUES.asString() == method.name
}
@@ -1,97 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationArgument;
import org.jetbrains.kotlin.load.java.structure.JavaClass;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import java.util.Collection;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.namedAnnotationArguments;
public class JavaAnnotationImpl extends JavaElementImpl<PsiAnnotation> implements JavaAnnotation {
public JavaAnnotationImpl(@NotNull PsiAnnotation psiAnnotation) {
super(psiAnnotation);
}
@Override
@NotNull
public Collection<JavaAnnotationArgument> getArguments() {
return namedAnnotationArguments(getPsi().getParameterList().getAttributes());
}
@Override
@Nullable
public ClassId getClassId() {
PsiClass resolved = resolvePsi();
if (resolved != null) return computeClassId(resolved);
// External annotations do not have PSI behind them,
// so we can only heuristically reconstruct annotation class ids from qualified names
String qualifiedName = getPsi().getQualifiedName();
if (qualifiedName != null) return ClassId.topLevel(new FqName(qualifiedName));
return null;
}
@Nullable
@Override
public JavaClass resolve() {
PsiClass resolved = resolvePsi();
return resolved == null ? null : new JavaClassImpl(resolved);
}
@Nullable
private static ClassId computeClassId(@NotNull PsiClass psiClass) {
PsiClass container = psiClass.getContainingClass();
if (container != null) {
ClassId parentClassId = computeClassId(container);
String name = psiClass.getName();
return parentClassId == null || name == null ? null : parentClassId.createNestedClassId(Name.identifier(name));
}
String fqName = psiClass.getQualifiedName();
return fqName == null ? null : ClassId.topLevel(new FqName(fqName));
}
@Nullable
private PsiClass resolvePsi() {
PsiJavaCodeReferenceElement referenceElement = getPsi().getNameReferenceElement();
if (referenceElement == null) return null;
PsiElement resolved = referenceElement.resolve();
return resolved instanceof PsiClass ? (PsiClass) resolved : null;
}
@Override
public boolean isIdeExternalAnnotation() {
PsiAnnotation psi = getPsi();
ExternalAnnotationsManager externalAnnotationManager = ExternalAnnotationsManager.getInstance(psi.getProject());
return externalAnnotationManager.isExternalAnnotation(psi);
}
}
@@ -1,26 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiAnnotationOwner;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotationOwner;
public interface JavaAnnotationOwnerImpl extends JavaAnnotationOwner {
@Nullable
PsiAnnotationOwner getAnnotationOwnerPsi();
}
@@ -1,33 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiArrayType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.load.java.structure.JavaArrayType;
public class JavaArrayTypeImpl extends JavaTypeImpl<PsiArrayType> implements JavaArrayType {
public JavaArrayTypeImpl(@NotNull PsiArrayType psiArrayType) {
super(psiArrayType);
}
@Override
@NotNull
public JavaTypeImpl<?> getComponentType() {
return JavaTypeImpl.create(getPsi().getComponentType());
}
}
@@ -1,138 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiTypeParameter
import com.intellij.psi.search.SearchScope
import org.jetbrains.kotlin.asJava.KtLightClassMarker
import org.jetbrains.kotlin.asJava.isSyntheticValuesOrValueOfMethod
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtPsiUtil
class JavaClassImpl(psiClass: PsiClass) : JavaClassifierImpl<PsiClass>(psiClass), VirtualFileBoundJavaClass, JavaAnnotationOwnerImpl, JavaModifierListOwnerImpl {
init {
assert(psiClass !is PsiTypeParameter) { "PsiTypeParameter should be wrapped in JavaTypeParameter, not JavaClass: use JavaClassifier.create()" }
}
override val innerClassNames: Collection<Name>
get() = psi.innerClasses.mapNotNull { it.name?.takeIf(Name::isValidIdentifier)?.let(Name::identifier) }
override fun findInnerClass(name: Name): JavaClass? {
return psi.findInnerClassByName(name.asString(), false)?.let(::JavaClassImpl)
}
override val fqName: FqName?
get() {
val qualifiedName = psi.qualifiedName
return if (qualifiedName == null) null else FqName(qualifiedName)
}
override val name: Name
get() = KtPsiUtil.safeName(psi.name)
override val isInterface: Boolean
get() = psi.isInterface
override val isAnnotationType: Boolean
get() = psi.isAnnotationType
override val isEnum: Boolean
get() = psi.isEnum
override val outerClass: JavaClassImpl?
get() {
val outer = psi.containingClass
return if (outer == null) null else JavaClassImpl(outer)
}
override val typeParameters: List<JavaTypeParameter>
get() = typeParameters(psi.typeParameters)
override val supertypes: Collection<JavaClassifierType>
get() = classifierTypes(psi.superTypes)
override val methods: Collection<JavaMethod>
get() {
assertNotLightClass()
// We apply distinct here because PsiClass#getMethods() can return duplicate PSI methods, for example in Lombok (see KT-11778)
// Return type seems to be null for example for the 'clone' Groovy method generated by @AutoClone (see EA-73795)
return methods(
psi.methods.filter { method ->
!method.isConstructor && method.returnType != null && !(isEnum && isSyntheticValuesOrValueOfMethod(method))
}
).distinct()
}
override val fields: Collection<JavaField>
get() {
assertNotLightClass()
return fields(psi.fields.filter {
// ex. Android plugin generates LightFields for resources started from '.' (.DS_Store file etc)
Name.isValidIdentifier(it.name)
})
}
override val constructors: Collection<JavaConstructor>
get() {
assertNotLightClass()
// See for example org.jetbrains.plugins.scala.lang.psi.light.ScFunctionWrapper,
// which is present in getConstructors(), but its isConstructor() returns false
return constructors(psi.constructors.filter { method -> method.isConstructor })
}
override fun hasDefaultConstructor() = !isInterface && constructors.isEmpty()
override val isAbstract: Boolean
get() = JavaElementUtil.isAbstract(this)
override val isStatic: Boolean
get() = JavaElementUtil.isStatic(this)
override val isFinal: Boolean
get() = JavaElementUtil.isFinal(this)
override val visibility: Visibility
get() = JavaElementUtil.getVisibility(this)
override val lightClassOriginKind: LightClassOriginKind?
get() = (psi as? KtLightClassMarker)?.originKind
override val virtualFile: VirtualFile?
get() = psi.containingFile?.virtualFile
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = psi.containingFile.virtualFile in scope
override fun getAnnotationOwnerPsi() = psi.modifierList
private fun assertNotLightClass() {
val psiClass = psi
if (psiClass !is KtLightClassMarker) return
val message = "Querying members of JavaClass created for $psiClass of type ${psiClass::class.java} defined in file ${psiClass.containingFile?.virtualFile?.canonicalPath}"
LOGGER.error(message)
}
companion object {
private val LOGGER = Logger.getInstance(JavaClassImpl::class.java)
}
}
@@ -1,60 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiTypeParameter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
import org.jetbrains.kotlin.load.java.structure.JavaClassifier;
import org.jetbrains.kotlin.name.FqName;
import java.util.Collection;
public abstract class JavaClassifierImpl<Psi extends PsiClass> extends JavaElementImpl<Psi> implements JavaClassifier, JavaAnnotationOwnerImpl {
protected JavaClassifierImpl(@NotNull Psi psiClass) {
super(psiClass);
}
@NotNull
/* package */ static JavaClassifierImpl<?> create(@NotNull PsiClass psiClass) {
if (psiClass instanceof PsiTypeParameter) {
return new JavaTypeParameterImpl((PsiTypeParameter) psiClass);
}
else {
return new JavaClassImpl(psiClass);
}
}
@NotNull
@Override
public Collection<JavaAnnotation> getAnnotations() {
return JavaElementUtil.getAnnotations(this);
}
@Nullable
@Override
public JavaAnnotation findAnnotation(@NotNull FqName fqName) {
return JavaElementUtil.findAnnotation(this, fqName);
}
@Override
public boolean isDeprecatedInJavaDoc() {
return getPsi().isDeprecated();
}
}
@@ -1,105 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl
import com.intellij.psi.*
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
import org.jetbrains.kotlin.load.java.structure.JavaType
import java.util.ArrayList
class JavaClassifierTypeImpl(psiClassType: PsiClassType) : JavaTypeImpl<PsiClassType>(psiClassType), JavaClassifierType {
private var resolutionResult: ResolutionResult? = null
override val classifier: JavaClassifierImpl<*>?
get() = resolve().classifier
val substitutor: PsiSubstitutor
get() = resolve().substitutor
override val classifierQualifiedName: String
get() = psi.canonicalText.convertCanonicalNameToQName()
override val presentableText: String
get() = psi.presentableText
override val isRaw: Boolean
get() = resolve().isRaw
override// parameters including ones from outer class
val typeArguments: List<JavaType?>
get() {
val classifier = classifier as? JavaClassImpl ?: return emptyList()
val parameters = getTypeParameters(classifier.psi)
val substitutor = substitutor
val result = ArrayList<JavaType?>(parameters.size)
for (typeParameter in parameters) {
val substitutedType = substitutor.substitute(typeParameter)
result.add(substitutedType?.let { JavaTypeImpl.create(it) })
}
return result
}
private class ResolutionResult(
val classifier: JavaClassifierImpl<*>?,
val substitutor: PsiSubstitutor,
val isRaw: Boolean
)
private fun resolve(): ResolutionResult {
return resolutionResult ?: run {
val result = psi.resolveGenerics()
val psiClass = result.element
val substitutor = result.substitutor
ResolutionResult(
psiClass?.let { JavaClassifierImpl.create(it) }, substitutor, PsiClassType.isRaw(result)
).apply {
resolutionResult = this
}
}
}
// Copy-pasted from PsiUtil.typeParametersIterable
// The only change is using `Collections.addAll(result, typeParameters)` instead of reversing type parameters of `currentOwner`
// Result differs in cases like:
// class Outer<H1> {
// class Inner<H2, H3> {}
// }
//
// PsiUtil.typeParametersIterable returns H3, H2, H1
// But we would like to have H2, H3, H1 as such order is consistent with our type representation
private fun getTypeParameters(owner: PsiClass): List<PsiTypeParameter> {
var result: List<PsiTypeParameter>? = null
var currentOwner: PsiTypeParameterListOwner? = owner
while (currentOwner != null) {
val typeParameters = currentOwner.typeParameters
if (typeParameters.isNotEmpty()) {
result = result?.let { it + typeParameters } ?: typeParameters.toList()
}
if (currentOwner.hasModifierProperty(PsiModifier.STATIC)) break
currentOwner = currentOwner.containingClass
}
return result ?: emptyList()
}
}
@@ -1,49 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiMethod;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.load.java.structure.JavaConstructor;
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter;
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter;
import java.util.List;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.typeParameters;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.valueParameters;
public class JavaConstructorImpl extends JavaMemberImpl<PsiMethod> implements JavaConstructor {
public JavaConstructorImpl(@NotNull PsiMethod psiMethod) {
super(psiMethod);
assert psiMethod.isConstructor() :
"PsiMethod which is not a constructor should not be wrapped in JavaConstructorImpl: " +
psiMethod.getName() + " " + psiMethod.getClass().getName();
}
@NotNull
@Override
public List<JavaValueParameter> getValueParameters() {
return valueParameters(getPsi().getParameterList().getParameters());
}
@NotNull
@Override
public List<JavaTypeParameter> getTypeParameters() {
return typeParameters(getPsi().getTypeParameters());
}
}
@@ -1,84 +0,0 @@
/*
* Copyright 2010-2016 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.
*/
@file:JvmName("JavaElementCollectionFromPsiArrayUtil")
package org.jetbrains.kotlin.load.java.structure.impl
import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.load.java.NULLABILITY_ANNOTATIONS
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
private inline fun <Psi, Java> Array<Psi>.convert(factory: (Psi) -> Java): List<Java> =
when (size) {
0 -> emptyList()
1 -> listOf(factory(first()))
else -> map(factory)
}
private fun <Psi, Java> Collection<Psi>.convert(factory: (Psi) -> Java): List<Java> =
when (size) {
0 -> emptyList()
1 -> listOf(factory(first()))
else -> map(factory)
}
internal fun classes(classes: Array<PsiClass>): Collection<JavaClass> =
classes.convert(::JavaClassImpl)
internal fun classes(classes: Collection<PsiClass>): Collection<JavaClass> =
classes.convert(::JavaClassImpl)
internal fun packages(packages: Array<PsiPackage>, scope: GlobalSearchScope): Collection<JavaPackage> =
packages.convert { psi -> JavaPackageImpl(psi, scope) }
internal fun methods(methods: Collection<PsiMethod>): Collection<JavaMethod> =
methods.convert(::JavaMethodImpl)
internal fun constructors(methods: Collection<PsiMethod>): Collection<JavaConstructor> =
methods.convert(::JavaConstructorImpl)
internal fun fields(fields: Collection<PsiField>): Collection<JavaField> =
fields.convert(::JavaFieldImpl)
internal fun valueParameters(parameters: Array<PsiParameter>): List<JavaValueParameter> =
parameters.convert(::JavaValueParameterImpl)
internal fun typeParameters(typeParameters: Array<PsiTypeParameter>): List<JavaTypeParameter> =
typeParameters.convert(::JavaTypeParameterImpl)
internal fun classifierTypes(classTypes: Array<PsiClassType>): Collection<JavaClassifierType> =
classTypes.convert(::JavaClassifierTypeImpl)
internal fun annotations(annotations: Array<out PsiAnnotation>): Collection<JavaAnnotation> =
annotations.convert(::JavaAnnotationImpl)
internal fun nullabilityAnnotations(annotations: Array<out PsiAnnotation>): Collection<JavaAnnotation> =
annotations.convert(::JavaAnnotationImpl)
.filter { annotation ->
val fqName = annotation.classId?.asSingleFqName() ?: return@filter false
fqName in NULLABILITY_ANNOTATIONS
}
internal fun namedAnnotationArguments(nameValuePairs: Array<PsiNameValuePair>): Collection<JavaAnnotationArgument> =
nameValuePairs.convert { psi ->
val name = psi.name?.let(Name::identifier)
val value = psi.value ?: error("Annotation argument value cannot be null: $name")
JavaAnnotationArgumentImpl.create(value, name)
}
@@ -1,49 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.load.java.structure.JavaElement;
public abstract class JavaElementImpl<Psi extends PsiElement> implements JavaElement {
private final Psi psiElement;
protected JavaElementImpl(@NotNull Psi psiElement) {
this.psiElement = psiElement;
}
@NotNull
public Psi getPsi() {
return psiElement;
}
@Override
public int hashCode() {
return getPsi().hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof JavaElementImpl && getPsi().equals(((JavaElementImpl) obj).getPsi());
}
@Override
public String toString() {
return getClass().getSimpleName() + ": " + getPsi();
}
}
@@ -1,109 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.codeInsight.ExternalAnnotationsManager;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiModifier;
import com.intellij.psi.PsiModifierListOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.Visibilities;
import org.jetbrains.kotlin.descriptors.Visibility;
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
import org.jetbrains.kotlin.name.FqName;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.annotations;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.nullabilityAnnotations;
/* package */ class JavaElementUtil {
private JavaElementUtil() {
}
public static boolean isAbstract(@NotNull JavaModifierListOwnerImpl owner) {
return owner.getPsi().hasModifierProperty(PsiModifier.ABSTRACT);
}
public static boolean isStatic(@NotNull JavaModifierListOwnerImpl owner) {
return owner.getPsi().hasModifierProperty(PsiModifier.STATIC);
}
public static boolean isFinal(@NotNull JavaModifierListOwnerImpl owner) {
return owner.getPsi().hasModifierProperty(PsiModifier.FINAL);
}
@NotNull
public static Visibility getVisibility(@NotNull JavaModifierListOwnerImpl owner) {
PsiModifierListOwner psiOwner = owner.getPsi();
if (psiOwner.hasModifierProperty(PsiModifier.PUBLIC)) {
return Visibilities.Public.INSTANCE;
}
if (psiOwner.hasModifierProperty(PsiModifier.PRIVATE)) {
return Visibilities.Private.INSTANCE;
}
if (psiOwner.hasModifierProperty(PsiModifier.PROTECTED)) {
return owner.isStatic() ? JavaVisibilities.ProtectedStaticVisibility.INSTANCE : JavaVisibilities.ProtectedAndPackage.INSTANCE;
}
return JavaVisibilities.PackageVisibility.INSTANCE;
}
@NotNull
public static Collection<JavaAnnotation> getAnnotations(@NotNull JavaAnnotationOwnerImpl owner) {
PsiAnnotationOwner annotationOwnerPsi = owner.getAnnotationOwnerPsi();
if (annotationOwnerPsi != null) {
return annotations(annotationOwnerPsi.getAnnotations());
}
return Collections.emptyList();
}
@Nullable
private static PsiAnnotation[] getExternalAnnotations(@NotNull JavaModifierListOwnerImpl modifierListOwner) {
PsiModifierListOwner psiModifierListOwner = modifierListOwner.getPsi();
ExternalAnnotationsManager externalAnnotationManager = ExternalAnnotationsManager
.getInstance(psiModifierListOwner.getProject());
return externalAnnotationManager.findExternalAnnotations(psiModifierListOwner);
}
@NotNull
static <T extends JavaAnnotationOwnerImpl & JavaModifierListOwnerImpl>
Collection<JavaAnnotation> getRegularAndExternalAnnotations(@NotNull T owner) {
PsiAnnotation[] externalAnnotations = getExternalAnnotations(owner);
if (externalAnnotations == null) {
return getAnnotations(owner);
}
Collection<JavaAnnotation> annotations = new ArrayList<>(getAnnotations(owner));
annotations.addAll(nullabilityAnnotations(externalAnnotations));
return annotations;
}
@Nullable
public static JavaAnnotation findAnnotation(@NotNull JavaAnnotationOwnerImpl owner, @NotNull FqName fqName) {
PsiAnnotationOwner annotationOwnerPsi = owner.getAnnotationOwnerPsi();
if (annotationOwnerPsi != null) {
PsiAnnotation psiAnnotation = annotationOwnerPsi.findAnnotation(fqName.asString());
return psiAnnotation == null ? null : new JavaAnnotationImpl(psiAnnotation);
}
return null;
}
}
@@ -1,56 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiEnumConstant;
import com.intellij.psi.PsiField;
import com.intellij.psi.PsiVariable;
import com.intellij.psi.util.PsiUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.JavaField;
import org.jetbrains.kotlin.load.java.structure.JavaType;
public class JavaFieldImpl extends JavaMemberImpl<PsiField> implements JavaField {
public JavaFieldImpl(@NotNull PsiField psiField) {
super(psiField);
}
@Override
public boolean isEnumEntry() {
return getPsi() instanceof PsiEnumConstant;
}
@Override
@NotNull
public JavaType getType() {
return JavaTypeImpl.create(getPsi().getType());
}
@Nullable
@Override
public Object getInitializerValue() {
return getPsi().computeConstantValue();
}
@Override
public boolean getHasConstantNotNullInitializer() {
// PsiUtil.isCompileTimeConstant returns false for null-initialized fields,
// see com.intellij.psi.util.IsConstantExpressionVisitor.visitLiteralExpression()
return PsiUtil.isCompileTimeConstant((PsiVariable) getPsi());
}
}
@@ -1,100 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiDocCommentOwner;
import com.intellij.psi.PsiMember;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.Visibility;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
import org.jetbrains.kotlin.load.java.structure.JavaClass;
import org.jetbrains.kotlin.load.java.structure.JavaMember;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import java.util.Collection;
public abstract class JavaMemberImpl<Psi extends PsiMember> extends JavaElementImpl<Psi>
implements JavaMember, JavaAnnotationOwnerImpl, JavaModifierListOwnerImpl {
protected JavaMemberImpl(@NotNull Psi psiMember) {
super(psiMember);
}
@Nullable
@Override
public PsiAnnotationOwner getAnnotationOwnerPsi() {
return getPsi().getModifierList();
}
@NotNull
@Override
public Name getName() {
String name = getPsi().getName();
assert name != null && Name.isValidIdentifier(name) : "Member must have a name: " + getPsi().getText();
return Name.identifier(name);
}
@NotNull
@Override
public JavaClass getContainingClass() {
PsiClass psiClass = getPsi().getContainingClass();
assert psiClass != null : "Member must have a containing class: " + getPsi();
return new JavaClassImpl(psiClass);
}
@Override
public boolean isAbstract() {
return JavaElementUtil.isAbstract(this);
}
@Override
public boolean isStatic() {
return JavaElementUtil.isStatic(this);
}
@Override
public boolean isFinal() {
return JavaElementUtil.isFinal(this);
}
@NotNull
@Override
public Visibility getVisibility() {
return JavaElementUtil.getVisibility(this);
}
@NotNull
@Override
public Collection<JavaAnnotation> getAnnotations() {
return JavaElementUtil.getRegularAndExternalAnnotations(this);
}
@Nullable
@Override
public JavaAnnotation findAnnotation(@NotNull FqName fqName) {
return JavaElementUtil.findAnnotation(this, fqName);
}
@Override
public boolean isDeprecatedInJavaDoc() {
PsiMember psi = getPsi();
return psi instanceof PsiDocCommentOwner && ((PsiDocCommentOwner) psi).isDeprecated();
}
}
@@ -1,85 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiAnnotationMemberValue;
import com.intellij.psi.PsiAnnotationMethod;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.*;
import org.jetbrains.kotlin.name.Name;
import java.util.List;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.typeParameters;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.valueParameters;
public class JavaMethodImpl extends JavaMemberImpl<PsiMethod> implements JavaMethod {
public JavaMethodImpl(@NotNull PsiMethod psiMethod) {
super(psiMethod);
assert !psiMethod.isConstructor() :
"PsiMethod which is a constructor should be wrapped in JavaConstructorImpl: " + psiMethod.getName();
}
@NotNull
@Override
public Name getName() {
return Name.identifier(getPsi().getName());
}
@NotNull
@Override
public List<JavaTypeParameter> getTypeParameters() {
return typeParameters(getPsi().getTypeParameters());
}
@Override
@NotNull
public List<JavaValueParameter> getValueParameters() {
return valueParameters(getPsi().getParameterList().getParameters());
}
@Override
@Nullable
public JavaAnnotationArgument getAnnotationParameterDefaultValue() {
PsiMethod psiMethod = getPsi();
if (psiMethod instanceof PsiAnnotationMethod) {
PsiAnnotationMemberValue defaultValue = ((PsiAnnotationMethod) psiMethod).getDefaultValue();
if (defaultValue != null) {
return JavaAnnotationArgumentImpl.Factory.create(defaultValue, null);
}
}
return null;
}
@Override
public boolean getHasAnnotationParameterDefaultValue() {
PsiMethod psiMethod = getPsi();
return psiMethod instanceof PsiAnnotationMethod && ((PsiAnnotationMethod) psiMethod).getDefaultValue() != null;
}
@Override
@NotNull
public JavaType getReturnType() {
PsiType psiType = getPsi().getReturnType();
assert psiType != null : "Method is not a constructor and has no return type: " + getName();
return JavaTypeImpl.create(psiType);
}
}
@@ -1,26 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiModifierListOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner;
public interface JavaModifierListOwnerImpl extends JavaModifierListOwner {
@NotNull
PsiModifierListOwner getPsi();
}
@@ -1,47 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl
import com.intellij.psi.PsiPackage
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
class JavaPackageImpl(
psiPackage: PsiPackage, private val scope: GlobalSearchScope
) : JavaElementImpl<PsiPackage>(psiPackage), JavaPackage, MapBasedJavaAnnotationOwner {
override fun getClasses(nameFilter: (Name) -> Boolean): Collection<JavaClass> {
val psiClasses = psi.getClasses(scope).filter {
val name = it.name
name != null && nameFilter(Name.identifier(name))
}
return classes(psiClasses)
}
override val subPackages: Collection<JavaPackage>
get() = packages(psi.getSubPackages(scope), scope)
override val fqName: FqName
get() = FqName(psi.qualifiedName)
override val annotations: Collection<JavaAnnotation>
get() = org.jetbrains.kotlin.load.java.structure.impl.annotations(psi.annotationList?.annotations.orEmpty())
override val annotationsByFqName: Map<FqName?, JavaAnnotation> by buildLazyValueForMap()
}
@@ -1,37 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiPrimitiveType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.builtins.PrimitiveType;
import org.jetbrains.kotlin.load.java.structure.JavaPrimitiveType;
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType;
public class JavaPrimitiveTypeImpl extends JavaTypeImpl<PsiPrimitiveType> implements JavaPrimitiveType {
public JavaPrimitiveTypeImpl(@NotNull PsiPrimitiveType psiPrimitiveType) {
super(psiPrimitiveType);
}
@Override
@Nullable
public PrimitiveType getType() {
String text = getPsi().getCanonicalText();
return "void".equals(text) ? null : JvmPrimitiveType.get(text).getPrimitiveType();
}
}
@@ -1,112 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
import org.jetbrains.kotlin.load.java.structure.JavaType;
import org.jetbrains.kotlin.name.FqName;
import java.util.Collection;
public abstract class JavaTypeImpl<Psi extends PsiType> implements JavaType, JavaAnnotationOwnerImpl {
private final Psi psiType;
public JavaTypeImpl(@NotNull Psi psiType) {
this.psiType = psiType;
}
@NotNull
public Psi getPsi() {
return psiType;
}
@Nullable
@Override
public PsiAnnotationOwner getAnnotationOwnerPsi() {
return getPsi();
}
@NotNull
public static JavaTypeImpl<?> create(@NotNull PsiType psiType) {
return psiType.accept(new PsiTypeVisitor<JavaTypeImpl<?>>() {
@Nullable
@Override
public JavaTypeImpl<?> visitType(@NotNull PsiType type) {
throw new UnsupportedOperationException("Unsupported PsiType: " + type);
}
@Nullable
@Override
public JavaTypeImpl<?> visitPrimitiveType(@NotNull PsiPrimitiveType primitiveType) {
return new JavaPrimitiveTypeImpl(primitiveType);
}
@Nullable
@Override
public JavaTypeImpl<?> visitArrayType(@NotNull PsiArrayType arrayType) {
return new JavaArrayTypeImpl(arrayType);
}
@Nullable
@Override
public JavaTypeImpl<?> visitClassType(@NotNull PsiClassType classType) {
return new JavaClassifierTypeImpl(classType);
}
@Nullable
@Override
public JavaTypeImpl<?> visitWildcardType(@NotNull PsiWildcardType wildcardType) {
return new JavaWildcardTypeImpl(wildcardType);
}
});
}
@NotNull
@Override
public Collection<JavaAnnotation> getAnnotations() {
return JavaElementUtil.getAnnotations(this);
}
@Nullable
@Override
public JavaAnnotation findAnnotation(@NotNull FqName fqName) {
return JavaElementUtil.findAnnotation(this, fqName);
}
@Override
public boolean isDeprecatedInJavaDoc() {
return false;
}
@Override
public int hashCode() {
return getPsi().hashCode();
}
@Override
public boolean equals(Object obj) {
return obj instanceof JavaTypeImpl && getPsi().equals(((JavaTypeImpl) obj).getPsi());
}
@Override
public String toString() {
return getClass().getSimpleName() + ": " + getPsi();
}
}
@@ -1,54 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiTypeParameter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType;
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.name.SpecialNames;
import java.util.Collection;
import static org.jetbrains.kotlin.load.java.structure.impl.JavaElementCollectionFromPsiArrayUtil.classifierTypes;
public class JavaTypeParameterImpl extends JavaClassifierImpl<PsiTypeParameter> implements JavaTypeParameter {
public JavaTypeParameterImpl(@NotNull PsiTypeParameter psiTypeParameter) {
super(psiTypeParameter);
}
@NotNull
@Override
public Name getName() {
return SpecialNames.safeIdentifier(getPsi().getName());
}
@Override
@NotNull
public Collection<JavaClassifierType> getUpperBounds() {
return classifierTypes(getPsi().getExtendsList().getReferencedTypes());
}
@Nullable
@Override
public PsiAnnotationOwner getAnnotationOwnerPsi() {
return getPsi();
}
}
@@ -1,106 +0,0 @@
/*
* Copyright 2010-2016 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiAnnotationOwner;
import com.intellij.psi.PsiParameter;
import com.intellij.psi.impl.compiled.ClsParameterImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.Visibilities;
import org.jetbrains.kotlin.descriptors.Visibility;
import org.jetbrains.kotlin.load.java.structure.JavaAnnotation;
import org.jetbrains.kotlin.load.java.structure.JavaType;
import org.jetbrains.kotlin.load.java.structure.JavaValueParameter;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name;
import java.util.Collection;
public class JavaValueParameterImpl extends JavaElementImpl<PsiParameter>
implements JavaValueParameter, JavaAnnotationOwnerImpl, JavaModifierListOwnerImpl {
public JavaValueParameterImpl(@NotNull PsiParameter psiParameter) {
super(psiParameter);
}
@Nullable
@Override
public PsiAnnotationOwner getAnnotationOwnerPsi() {
return getPsi().getModifierList();
}
@Override
public boolean isAbstract() {
return false;
}
@Override
public boolean isStatic() {
return false;
}
@Override
public boolean isFinal() {
return false;
}
@NotNull
@Override
public Visibility getVisibility() {
return Visibilities.Local.INSTANCE;
}
@NotNull
@Override
public Collection<JavaAnnotation> getAnnotations() {
return JavaElementUtil.getRegularAndExternalAnnotations(this);
}
@Nullable
@Override
public JavaAnnotation findAnnotation(@NotNull FqName fqName) {
return JavaElementUtil.findAnnotation(this, fqName);
}
@Override
public boolean isDeprecatedInJavaDoc() {
return false;
}
@Override
@Nullable
public Name getName() {
PsiParameter psi = getPsi();
if (psi instanceof ClsParameterImpl && ((ClsParameterImpl) psi).isAutoGeneratedName()) {
return null;
}
String name = psi.getName();
return name == null ? null : Name.identifier(name);
}
@Override
@NotNull
public JavaType getType() {
return JavaTypeImpl.create(getPsi().getType());
}
@Override
public boolean isVararg() {
return getPsi().isVarArgs();
}
}
@@ -1,41 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiWildcardType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.load.java.structure.JavaWildcardType;
public class JavaWildcardTypeImpl extends JavaTypeImpl<PsiWildcardType> implements JavaWildcardType {
public JavaWildcardTypeImpl(@NotNull PsiWildcardType psiWildcardType) {
super(psiWildcardType);
}
@Override
@Nullable
public JavaTypeImpl<?> getBound() {
PsiType bound = getPsi().getBound();
return bound == null ? null : create(bound);
}
@Override
public boolean isExtends() {
return getPsi().isExtends();
}
}
@@ -1,27 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.SearchScope
import org.jetbrains.kotlin.load.java.structure.JavaClass
interface VirtualFileBoundJavaClass : JavaClass {
val virtualFile: VirtualFile?
fun isFromSourceCodeInScope(scope: SearchScope): Boolean
}
@@ -1,97 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.load.java.structure.impl
import com.intellij.psi.*
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
abstract class JavaAnnotationArgumentImpl(
override val name: Name?
) : JavaAnnotationArgument {
companion object Factory {
fun create(argument: PsiAnnotationMemberValue, name: Name?): JavaAnnotationArgument {
if (argument is PsiClassObjectAccessExpression) {
return JavaClassObjectAnnotationArgumentImpl(argument, name)
}
val value = JavaPsiFacade.getInstance(argument.project).constantEvaluationHelper.computeConstantExpression(argument)
if (value is Enum<*>) {
return JavaEnumValueAnnotationArgumentImpl(argument as PsiReferenceExpression, name)
}
if (value != null || argument is PsiLiteralExpression) {
return JavaLiteralAnnotationArgumentImpl(name, value)
}
return when (argument) {
is PsiReferenceExpression -> JavaEnumValueAnnotationArgumentImpl(argument, name)
is PsiArrayInitializerMemberValue -> JavaArrayAnnotationArgumentImpl(argument, name)
is PsiAnnotation -> JavaAnnotationAsAnnotationArgumentImpl(argument, name)
else -> throw UnsupportedOperationException("Unsupported annotation argument type: " + argument)
}
}
}
}
class JavaLiteralAnnotationArgumentImpl(
override val name: Name?,
override val value: Any?
) : JavaLiteralAnnotationArgument
class JavaArrayAnnotationArgumentImpl(
private val psiValue: PsiArrayInitializerMemberValue,
name: Name?
) : JavaAnnotationArgumentImpl(name), JavaArrayAnnotationArgument {
override fun getElements() = psiValue.initializers.map { JavaAnnotationArgumentImpl.create(it, null) }
}
class JavaEnumValueAnnotationArgumentImpl(
private val psiReference: PsiReferenceExpression,
name: Name?
) : JavaAnnotationArgumentImpl(name), JavaEnumValueAnnotationArgument {
override val enumClassId: ClassId?
get() {
val element = psiReference.resolve()
if (element is PsiEnumConstant) {
return JavaFieldImpl(element).containingClass.classId
}
val fqName = (psiReference.qualifier as? PsiReferenceExpression)?.qualifiedName ?: return null
// TODO: find a way to construct a correct name (with nested classes) for unresolved enums
return ClassId.topLevel(FqName(fqName))
}
override val entryName: Name?
get() = psiReference.referenceName?.let(Name::identifier)
}
class JavaClassObjectAnnotationArgumentImpl(
private val psiExpression: PsiClassObjectAccessExpression,
name: Name?
) : JavaAnnotationArgumentImpl(name), JavaClassObjectAnnotationArgument {
override fun getReferencedType() = JavaTypeImpl.create(psiExpression.operand.type)
}
class JavaAnnotationAsAnnotationArgumentImpl(
private val psiAnnotation: PsiAnnotation,
name: Name?
) : JavaAnnotationArgumentImpl(name), JavaAnnotationAsAnnotationArgument {
override fun getAnnotation() = JavaAnnotationImpl(psiAnnotation)
}
@@ -1,260 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.org.objectweb.asm.*
import java.lang.reflect.Array
internal class AnnotationsAndParameterCollectorMethodVisitor(
private val member: BinaryJavaMethodBase,
private val context: ClassifierResolutionContext,
private val signatureParser: BinaryClassSignatureParser,
private val parametersToSkipNumber: Int,
private val parametersCountInMethodDesc: Int
) : MethodVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
private var parameterIndex = 0
private var visibleAnnotableParameterCount = parametersCountInMethodDesc
private var invisibleAnnotableParameterCount = parametersCountInMethodDesc
override fun visitAnnotationDefault(): AnnotationVisitor? =
BinaryJavaAnnotationVisitor(context, signatureParser) {
member.safeAs<BinaryJavaMethod>()?.annotationParameterDefaultValue = it
}
override fun visitParameter(name: String?, access: Int) {
if (name != null) {
val index = parameterIndex - parametersToSkipNumber
if (index >= 0) {
val parameter = member.valueParameters.getOrNull(index) ?: error(
"No parameter with index $parameterIndex-$parametersToSkipNumber (name=$name access=$access) " +
"in method ${member.containingClass.fqName}.${member.name}"
)
parameter.updateName(Name.identifier(name))
}
}
parameterIndex++
}
override fun visitAnnotation(desc: String, visible: Boolean) =
BinaryJavaAnnotation.addAnnotation(
member.annotations as MutableCollection<JavaAnnotation>,
desc, context, signatureParser
)
@Suppress("NOTHING_TO_OVERRIDE")
override fun visitAnnotableParameterCount(parameterCount: Int, visible: Boolean) {
if (visible) {
visibleAnnotableParameterCount = parameterCount
} else {
invisibleAnnotableParameterCount = parameterCount
}
}
override fun visitParameterAnnotation(parameter: Int, desc: String, visible: Boolean): AnnotationVisitor? {
val absoluteParameterIndex =
parameter + parametersCountInMethodDesc - if (visible) visibleAnnotableParameterCount else invisibleAnnotableParameterCount
val index = absoluteParameterIndex - parametersToSkipNumber
if (index < 0) return null
val annotations =
member.valueParameters[index].annotations as MutableCollection<JavaAnnotation>?
?: return null
return BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
}
override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, desc: String, visible: Boolean): AnnotationVisitor? {
// TODO: support annotations on type arguments
if (typePath != null) return null
val typeReference = TypeReference(typeRef)
return when (typeReference.sort) {
TypeReference.METHOD_RETURN -> member.safeAs<BinaryJavaMethod>()?.returnType?.let {
BinaryJavaAnnotation.addTypeAnnotation(it, desc, context, signatureParser)
}
TypeReference.METHOD_FORMAL_PARAMETER ->
BinaryJavaAnnotation.addTypeAnnotation(
member.valueParameters[typeReference.formalParameterIndex].type,
desc, context, signatureParser
)
else -> null
}
}
}
class BinaryJavaAnnotation private constructor(
desc: String,
private val context: ClassifierResolutionContext,
override val arguments: Collection<JavaAnnotationArgument>
) : JavaAnnotation {
companion object {
fun createAnnotationAndVisitor(
desc: String,
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): Pair<JavaAnnotation, AnnotationVisitor> {
val arguments = mutableListOf<JavaAnnotationArgument>()
val annotation = BinaryJavaAnnotation(desc, context, arguments)
return annotation to BinaryJavaAnnotationVisitor(context, signatureParser, arguments)
}
fun addAnnotation(
annotations: MutableCollection<JavaAnnotation>,
desc: String,
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): AnnotationVisitor {
val (javaAnnotation, annotationVisitor) = createAnnotationAndVisitor(desc, context, signatureParser)
annotations.add(javaAnnotation)
return annotationVisitor
}
fun addTypeAnnotation(
type: JavaType,
desc: String,
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): AnnotationVisitor? {
type as? PlainJavaClassifierType ?: return null
val (javaAnnotation, annotationVisitor) = createAnnotationAndVisitor(desc, context, signatureParser)
type.addAnnotation(javaAnnotation)
return annotationVisitor
}
}
private val classifierResolutionResult by lazy(LazyThreadSafetyMode.NONE) {
context.resolveByInternalName(Type.getType(desc).internalName)
}
override val classId: ClassId?
get() = classifierResolutionResult.classifier.safeAs<JavaClass>()?.classId
?: ClassId.topLevel(FqName(classifierResolutionResult.qualifiedName))
override fun resolve() = classifierResolutionResult.classifier as? JavaClass
}
class BinaryJavaAnnotationVisitor(
private val context: ClassifierResolutionContext,
private val signatureParser: BinaryClassSignatureParser,
private val sink: (JavaAnnotationArgument) -> Unit
) : AnnotationVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
constructor(
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser,
arguments: MutableCollection<JavaAnnotationArgument>
) : this(context, signatureParser, { arguments.add(it) })
private fun addArgument(argument: JavaAnnotationArgument?) {
if (argument != null) {
sink(argument)
}
}
override fun visitAnnotation(name: String?, desc: String): AnnotationVisitor {
val (annotation, visitor) = BinaryJavaAnnotation.createAnnotationAndVisitor(desc, context, signatureParser)
sink(PlainJavaAnnotationAsAnnotationArgument(name, annotation))
return visitor
}
override fun visitEnum(name: String?, desc: String, value: String) {
val enumClassId = context.mapInternalNameToClassId(Type.getType(desc).internalName)
addArgument(PlainJavaEnumValueAnnotationArgument(name, enumClassId, value))
}
override fun visit(name: String?, value: Any?) {
addArgument(convertConstValue(name, value))
}
private fun convertConstValue(name: String?, value: Any?): JavaAnnotationArgument? {
return when (value) {
is Byte, is Boolean, is Char, is Short, is Int, is Long, is Float, is Double, is String ->
PlainJavaLiteralAnnotationArgument(name, value)
is Type -> PlainJavaClassObjectAnnotationArgument(name, value, signatureParser, context)
else -> value?.takeIf { it.javaClass.isArray }?.let { array ->
val arguments = (0 until Array.getLength(array)).mapNotNull { index ->
convertConstValue(name = null, value = Array.get(array, index))
}
PlainJavaArrayAnnotationArgument(name, arguments)
}
}
}
override fun visitArray(name: String?): AnnotationVisitor {
val result = mutableListOf<JavaAnnotationArgument>()
addArgument(PlainJavaArrayAnnotationArgument(name, result))
return BinaryJavaAnnotationVisitor(context, signatureParser, result)
}
}
abstract class PlainJavaAnnotationArgument(name: String?) : JavaAnnotationArgument {
override val name: Name? = name?.takeIf(Name::isValidIdentifier)?.let(Name::identifier)
}
class PlainJavaLiteralAnnotationArgument(
name: String?,
override val value: Any?
) : PlainJavaAnnotationArgument(name), JavaLiteralAnnotationArgument
class PlainJavaClassObjectAnnotationArgument(
name: String?,
private val type: Type,
private val signatureParser: BinaryClassSignatureParser,
private val context: ClassifierResolutionContext
) : PlainJavaAnnotationArgument(name), JavaClassObjectAnnotationArgument {
override fun getReferencedType() = signatureParser.mapAsmType(type, context)
}
class PlainJavaArrayAnnotationArgument(
name: String?,
private val elements: List<JavaAnnotationArgument>
) : PlainJavaAnnotationArgument(name), JavaArrayAnnotationArgument {
override fun getElements(): List<JavaAnnotationArgument> = elements
}
class PlainJavaAnnotationAsAnnotationArgument(
name: String?,
private val annotation: JavaAnnotation
) : PlainJavaAnnotationArgument(name), JavaAnnotationAsAnnotationArgument {
override fun getAnnotation() = annotation
}
class PlainJavaEnumValueAnnotationArgument(
name: String?,
override val enumClassId: ClassId,
entryName: String
) : PlainJavaAnnotationArgument(name), JavaEnumValueAnnotationArgument {
override val entryName = Name.identifier(entryName)
}
@@ -1,224 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import com.intellij.util.containers.StringInterner
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.load.java.structure.JavaClassifierType
import org.jetbrains.kotlin.load.java.structure.JavaType
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
import org.jetbrains.kotlin.utils.compact
import org.jetbrains.org.objectweb.asm.Type
import java.text.CharacterIterator
import java.text.StringCharacterIterator
/**
* Take a look at com.intellij.psi.impl.compiled.SignatureParsing
* NOTE: currently this class can simply be converted to an object, but there are postponed plans
* to introduce cached instance for java.lang.Object type that would require injected class finder.
* So please, do not convert it to object
*/
class BinaryClassSignatureParser {
private val canonicalNameInterner = StringInterner()
fun parseTypeParametersDeclaration(signature: CharacterIterator, context: ClassifierResolutionContext): List<JavaTypeParameter> {
if (signature.current() != '<') {
return emptyList()
}
val typeParameters = arrayListOf<JavaTypeParameter>()
signature.next()
while (signature.current() != '>') {
typeParameters.add(parseTypeParameter(signature, context))
}
signature.next()
return typeParameters.compact()
}
private fun parseTypeParameter(signature: CharacterIterator, context: ClassifierResolutionContext): JavaTypeParameter {
val name = StringBuilder()
while (signature.current() != ':' && signature.current() != CharacterIterator.DONE) {
name.append(signature.current())
signature.next()
}
if (signature.current() == CharacterIterator.DONE) {
throw ClsFormatException()
}
val parameterName = name.toString()
// postpone list allocation till a second bound is seen; ignore sole Object bound
val bounds: MutableList<JavaClassifierType> = SmartList()
while (signature.current() == ':') {
signature.next()
val bound = parseClassifierRefSignature(signature, context) ?: continue
bounds.add(bound)
}
return BinaryJavaTypeParameter(Name.identifier(parameterName), bounds)
}
fun parseClassifierRefSignature(signature: CharacterIterator, context: ClassifierResolutionContext): JavaClassifierType? {
return when (signature.current()) {
'L' -> parseParameterizedClassRefSignature(signature, context)
'T' -> parseTypeVariableRefSignature(signature, context)
else -> null
}
}
private fun parseTypeVariableRefSignature(signature: CharacterIterator, context: ClassifierResolutionContext): JavaClassifierType? {
val id = StringBuilder()
signature.next()
while (signature.current() != ';' && signature.current() != '>' && signature.current() != CharacterIterator.DONE) {
id.append(signature.current())
signature.next()
}
if (signature.current() == CharacterIterator.DONE) {
throw ClsFormatException()
}
if (signature.current() == ';') {
signature.next()
}
val parameterName = canonicalNameInterner.intern(id.toString())
return PlainJavaClassifierType({ context.resolveTypeParameter(parameterName) }, emptyList())
}
private fun parseParameterizedClassRefSignature(
signature: CharacterIterator,
context: ClassifierResolutionContext
): JavaClassifierType {
val canonicalName = StringBuilder()
val argumentGroups = SmartList<List<JavaType>>()
signature.next()
while (signature.current() != ';' && signature.current() != CharacterIterator.DONE) {
val c = signature.current()
if (c == '<') {
val group = mutableListOf<JavaType>()
signature.next()
do {
group.add(parseClassOrTypeVariableElement(signature, context))
}
while (signature.current() != '>')
argumentGroups.add(group)
}
else if (c != ' ') {
canonicalName.append(c)
}
signature.next()
}
if (signature.current() == CharacterIterator.DONE) {
throw ClsFormatException()
}
signature.next()
val internalName = canonicalNameInterner.intern(canonicalName.toString().replace('.', '$'))
return PlainJavaClassifierType(
{ context.resolveByInternalName(internalName) },
argumentGroups.reversed().flattenTo(arrayListOf()).compact()
)
}
private fun parseClassOrTypeVariableElement(signature: CharacterIterator, context: ClassifierResolutionContext): JavaType {
val variance = parseVariance(signature)
if (variance == JavaSignatureVariance.STAR) {
return PlainJavaWildcardType(bound = null, isExtends = true)
}
val type = parseTypeString(signature, context)
if (variance == JavaSignatureVariance.NO_VARIANCE) return type
return PlainJavaWildcardType(type, isExtends = variance == JavaSignatureVariance.PLUS)
}
private enum class JavaSignatureVariance {
PLUS, MINUS, STAR, NO_VARIANCE
}
private fun parseVariance(signature: CharacterIterator): JavaSignatureVariance {
var advance = true
val variance = when (signature.current()) {
'+' -> JavaSignatureVariance.PLUS
'-' -> JavaSignatureVariance.MINUS
'*' -> JavaSignatureVariance.STAR
'.', '=' -> JavaSignatureVariance.NO_VARIANCE
else -> {
advance = false
JavaSignatureVariance.NO_VARIANCE
}
}
if (advance) {
signature.next()
}
return variance
}
private fun parseDimensions(signature: CharacterIterator): Int {
var dimensions = 0
while (signature.current() == '[') {
dimensions++
signature.next()
}
return dimensions
}
fun parseTypeString(signature: CharacterIterator, context: ClassifierResolutionContext): JavaType {
val dimensions = parseDimensions(signature)
val type: JavaType = parseTypeWithoutVarianceAndArray(signature, context) ?: throw ClsFormatException()
return (1..dimensions).fold(type) { result, _ -> PlainJavaArrayType(result) }
}
fun mapAsmType(type: Type, context: ClassifierResolutionContext) = parseTypeString(StringCharacterIterator(type.descriptor), context)
private fun parseTypeWithoutVarianceAndArray(signature: CharacterIterator, context: ClassifierResolutionContext) =
when (signature.current()) {
'L' -> parseParameterizedClassRefSignature(signature, context)
'T' -> parseTypeVariableRefSignature(signature, context)
'B' -> parsePrimitiveType(signature, PrimitiveType.BYTE)
'C' -> parsePrimitiveType(signature, PrimitiveType.CHAR)
'D' -> parsePrimitiveType(signature, PrimitiveType.DOUBLE)
'F' -> parsePrimitiveType(signature, PrimitiveType.FLOAT)
'I' -> parsePrimitiveType(signature, PrimitiveType.INT)
'J' -> parsePrimitiveType(signature, PrimitiveType.LONG)
'Z' -> parsePrimitiveType(signature, PrimitiveType.BOOLEAN)
'S' -> parsePrimitiveType(signature, PrimitiveType.SHORT)
'V' -> parsePrimitiveType(signature, null)
else -> null
}
private fun parsePrimitiveType(signature: CharacterIterator, primitiveType: PrimitiveType?): JavaType {
signature.next()
return PlainJavaPrimitiveType(primitiveType)
}
class ClsFormatException(message: String? = null, cause: Throwable? = null) : Throwable(message, cause)
}
@@ -1,221 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.search.SearchScope
import gnu.trove.THashMap
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.impl.VirtualFileBoundJavaClass
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.org.objectweb.asm.*
import java.text.CharacterIterator
import java.text.StringCharacterIterator
class BinaryJavaClass(
override val virtualFile: VirtualFile,
override val fqName: FqName,
internal val context: ClassifierResolutionContext,
private val signatureParser: BinaryClassSignatureParser,
override var access: Int = 0,
override val outerClass: JavaClass?,
classContent: ByteArray? = null
) : ClassVisitor(ASM_API_VERSION_FOR_CLASS_READING), VirtualFileBoundJavaClass, BinaryJavaModifierListOwner, MapBasedJavaAnnotationOwner {
private lateinit var myInternalName: String
override val annotations: MutableCollection<JavaAnnotation> = SmartList()
override lateinit var typeParameters: List<JavaTypeParameter>
override lateinit var supertypes: Collection<JavaClassifierType>
override val methods = arrayListOf<JavaMethod>()
override val fields = arrayListOf<JavaField>()
override val constructors = arrayListOf<JavaConstructor>()
override fun hasDefaultConstructor() = false // never: all constructors explicit in bytecode
override val annotationsByFqName by buildLazyValueForMap()
// Short name of a nested class of this class -> access flags as seen in the InnerClasses attribute value.
// Note that it doesn't include classes mentioned in other InnerClasses attribute values (those which are not nested in this class).
private val ownInnerClassNameToAccess: MutableMap<Name, Int> = THashMap()
override val innerClassNames get() = ownInnerClassNameToAccess.keys
override val name: Name
get() = fqName.shortName()
override val isInterface get() = isSet(Opcodes.ACC_INTERFACE)
override val isAnnotationType get() = isSet(Opcodes.ACC_ANNOTATION)
override val isEnum get() = isSet(Opcodes.ACC_ENUM)
override val lightClassOriginKind: LightClassOriginKind? get() = null
override fun isFromSourceCodeInScope(scope: SearchScope): Boolean = false
override fun visitEnd() {
methods.trimToSize()
fields.trimToSize()
constructors.trimToSize()
}
init {
try {
ClassReader(classContent ?: virtualFile.contentsToByteArray()).accept(
this,
ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
)
} catch (e: Throwable) {
throw IllegalStateException("Could not read class: $virtualFile", e)
}
}
override fun visitMethod(access: Int, name: String, desc: String, signature: String?, exceptions: Array<out String>?): MethodVisitor? {
if (access.isSet(Opcodes.ACC_SYNTHETIC) || access.isSet(Opcodes.ACC_BRIDGE) || name == "<clinit>") return null
// skip semi-synthetic enum methods
if (isEnum) {
if (name == "values" && desc.startsWith("()")) return null
if (name == "valueOf" && desc.startsWith("(Ljava/lang/String;)")) return null
}
val (member, visitor) = BinaryJavaMethodBase.create(name, access, desc, signature, this, context.copyForMember(), signatureParser)
when (member) {
is JavaMethod -> methods.add(member)
is JavaConstructor -> constructors.add(member)
else -> error("Unexpected member: ${member.javaClass}")
}
return visitor
}
override fun visitInnerClass(name: String, outerName: String?, innerName: String?, access: Int) {
if (access.isSet(Opcodes.ACC_SYNTHETIC)) return
if (innerName == null || outerName == null) return
// Do not read InnerClasses attribute values where full name != outer + $ + inner; treat those classes as top level instead.
// This is possible for example for Groovy-generated $Trait$FieldHelper classes.
if (name == "$outerName$$innerName") {
context.addInnerClass(name, outerName, innerName)
if (myInternalName == outerName) {
ownInnerClassNameToAccess[context.mapInternalNameToClassId(name).shortClassName] = access
}
}
}
override fun visit(
version: Int,
access: Int,
name: String,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
this.access = this.access or access
this.myInternalName = name
if (signature != null) {
parseClassSignature(signature)
} else {
this.typeParameters = emptyList()
this.supertypes = mutableListOf<JavaClassifierType>().apply {
addIfNotNull(superName?.convertInternalNameToClassifierType())
interfaces?.forEach {
addIfNotNull(it.convertInternalNameToClassifierType())
}
}
}
}
private fun parseClassSignature(signature: String) {
val iterator = StringCharacterIterator(signature)
this.typeParameters =
signatureParser
.parseTypeParametersDeclaration(iterator, context)
.also(context::addTypeParameters)
val supertypes = SmartList<JavaClassifierType>()
supertypes.addIfNotNull(signatureParser.parseClassifierRefSignature(iterator, context))
while (iterator.current() != CharacterIterator.DONE) {
supertypes.addIfNotNull(signatureParser.parseClassifierRefSignature(iterator, context))
}
this.supertypes = supertypes
}
private fun String.convertInternalNameToClassifierType(): JavaClassifierType =
PlainJavaClassifierType({ context.resolveByInternalName(this) }, emptyList())
override fun visitField(access: Int, name: String, desc: String, signature: String?, value: Any?): FieldVisitor? {
if (access.isSet(Opcodes.ACC_SYNTHETIC)) return null
val type = signatureParser.parseTypeString(StringCharacterIterator(signature ?: desc), context)
val processedValue = processValue(value, type)
return BinaryJavaField(Name.identifier(name), access, this, access.isSet(Opcodes.ACC_ENUM), type, processedValue).run {
fields.add(this)
object : FieldVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
override fun visitAnnotation(desc: String, visible: Boolean) =
BinaryJavaAnnotation.addAnnotation(this@run.annotations, desc, context, signatureParser)
override fun visitTypeAnnotation(typeRef: Int, typePath: TypePath?, desc: String, visible: Boolean) =
if (typePath == null)
BinaryJavaAnnotation.addTypeAnnotation(type, desc, context, signatureParser)
else
null
}
}
}
/**
* All the int-like values (including Char/Boolean) come in visitor as Integer instances
*/
private fun processValue(value: Any?, fieldType: JavaType): Any? {
if (fieldType !is JavaPrimitiveType || fieldType.type == null || value !is Int) return value
return when (fieldType.type) {
PrimitiveType.BOOLEAN -> {
when (value) {
0 -> false
1 -> true
else -> value
}
}
PrimitiveType.CHAR -> value.toChar()
else -> value
}
}
override fun visitAnnotation(desc: String, visible: Boolean) =
BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
override fun findInnerClass(name: Name): JavaClass? = findInnerClass(name, classFileContent = null)
fun findInnerClass(name: Name, classFileContent: ByteArray?): JavaClass? {
val access = ownInnerClassNameToAccess[name] ?: return null
return virtualFile.parent.findChild("${virtualFile.nameWithoutExtension}$$name.class")?.let {
BinaryJavaClass(
it, fqName.child(name), context.copyForMember(), signatureParser, access, this,
classFileContent
)
}
}
}
@@ -1,122 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.load.java.structure.JavaClassifier
import org.jetbrains.kotlin.load.java.structure.JavaTypeParameter
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.util.javaslang.ImmutableHashMap
import org.jetbrains.kotlin.util.javaslang.ImmutableMap
import org.jetbrains.kotlin.util.javaslang.getOrNull
import org.jetbrains.kotlin.utils.SmartList
typealias ClassIdToJavaClass = (ClassId) -> JavaClass?
class ClassifierResolutionContext private constructor(
private val classesByQName: ClassIdToJavaClass,
// Note that this data is fully mutable and its correctness is based on the assumption
// that nobody starts resolving classifier until type parameters and inner classes are initialized.
// Currently it's implemented through laziness in the PlainJavaClassifierType.
private var typeParameters: ImmutableMap<String, JavaTypeParameter>,
private var innerClasses: ImmutableMap<String, InnerClassInfo>
) {
constructor(classesByQName: ClassIdToJavaClass) : this(classesByQName, ImmutableHashMap.empty(), ImmutableHashMap.empty())
internal data class Result(val classifier: JavaClassifier?, val qualifiedName: String)
private class InnerClassInfo(val outerInternalName: String, val simpleName: String)
internal fun addInnerClass(innerInternalName: String, outerInternalName: String, simpleName: String) {
innerClasses = innerClasses.put(innerInternalName, InnerClassInfo(outerInternalName, simpleName))
}
internal fun addTypeParameters(newTypeParameters: Collection<JavaTypeParameter>) {
if (newTypeParameters.isEmpty()) return
typeParameters =
newTypeParameters
.fold(typeParameters) { acc, typeParameter ->
acc.put(typeParameter.name.identifier, typeParameter)
}
}
private fun resolveClass(classId: ClassId) = Result(classesByQName(classId), classId.asSingleFqName().asString())
internal fun resolveTypeParameter(name: String) = Result(typeParameters.getOrNull(name), name)
internal fun copyForMember() = ClassifierResolutionContext(classesByQName, typeParameters, innerClasses)
internal fun mapInternalNameToClassId(internalName: String): ClassId {
if ('$' in internalName) {
val innerClassInfo = innerClasses.getOrNull(internalName)
if (innerClassInfo != null && Name.isValidIdentifier(innerClassInfo.simpleName)) {
val outerClassId = mapInternalNameToClassId(innerClassInfo.outerInternalName)
return outerClassId.createNestedClassId(Name.identifier(innerClassInfo.simpleName))
}
}
return ClassId.topLevel(FqName(internalName.replace('/', '.')))
}
// See com.intellij.psi.impl.compiled.StubBuildingVisitor.GUESSING_MAPPER
private fun convertNestedClassInternalNameWithSimpleHeuristic(internalName: String): ClassId? {
val splitPoints = SmartList<Int>()
for (p in 0 until internalName.length) {
val c = internalName[p]
if (c == '$' && p > 0 && internalName[p - 1] != '/' && p < internalName.length - 1 && internalName[p + 1] != '$') {
splitPoints.add(p)
}
}
if (splitPoints.isEmpty()) return null
val substrings = (listOf(-1) + splitPoints).zip(splitPoints + internalName.length).map { (from, to) ->
internalName.substring(from + 1, to)
}
val outerFqName = FqName(substrings[0].replace('/', '.'))
val packageFqName = outerFqName.parent()
val relativeName = FqName(outerFqName.shortName().asString() + "." + substrings.subList(1, substrings.size).joinToString("."))
return ClassId(packageFqName, relativeName, false)
}
internal fun resolveByInternalName(internalName: String): Result {
val result = resolveClass(mapInternalNameToClassId(internalName))
if (result.classifier == null && '$' in internalName) {
// Class files generated by some (non-javac) compilers lack the InnerClasses attribute which would make it possible to
// unambiguously determine how to parse a particular internal name found in the class file. For example, see
// https://issues.apache.org/jira/browse/GROOVY-8863. In this case, we're trying to treat all dollar characters in the class
// name as nested class separators, lookup the class with that ClassId, and see if its InnerClasses attribute confirms our
// suspicion that this class was in fact nested.
val heuristicName = convertNestedClassInternalNameWithSimpleHeuristic(internalName)
if (heuristicName != null) {
val heuristicResult = resolveClass(heuristicName)
if (heuristicResult.classifier is BinaryJavaClass) {
val realName = heuristicResult.classifier.context.mapInternalNameToClassId(internalName)
if (heuristicName == realName) {
return heuristicResult
}
}
}
}
return result
}
}
@@ -1,188 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import com.intellij.util.cls.ClsFormatException
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.compact
import org.jetbrains.org.objectweb.asm.MethodVisitor
import org.jetbrains.org.objectweb.asm.Opcodes
import org.jetbrains.org.objectweb.asm.Type
import java.text.CharacterIterator
import java.text.StringCharacterIterator
abstract class BinaryJavaMethodBase(
override val access: Int,
override val containingClass: JavaClass,
val valueParameters: List<BinaryJavaValueParameter>,
val typeParameters: List<JavaTypeParameter>,
override val name: Name
) : JavaMember, MapBasedJavaAnnotationOwner, BinaryJavaModifierListOwner {
override val annotationsByFqName by buildLazyValueForMap()
override val annotations: Collection<JavaAnnotation> = SmartList()
companion object {
private class MethodInfo(
val returnType: JavaType,
val typeParameters: List<JavaTypeParameter>,
val valueParameterTypes: List<JavaType>
)
fun create(
name: String,
access: Int,
desc: String,
signature: String?,
containingClass: JavaClass,
parentContext: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): Pair<JavaMember, MethodVisitor> {
val isConstructor = "<init>" == name
val isVarargs = access.isSet(Opcodes.ACC_VARARGS)
val isInnerClassConstructor = isConstructor && containingClass.outerClass != null && !containingClass.isStatic
val isEnumConstructor = containingClass.isEnum && isConstructor
val info: MethodInfo =
if (signature != null) {
val contextForMethod = parentContext.copyForMember()
parseMethodSignature(signature, signatureParser, contextForMethod).also {
contextForMethod.addTypeParameters(it.typeParameters)
}
} else
parseMethodDescription(desc, parentContext, signatureParser).let {
when {
isEnumConstructor ->
// skip ordinal/name parameters for enum constructors
MethodInfo(it.returnType, it.typeParameters, it.valueParameterTypes.drop(2))
isInnerClassConstructor ->
// omit synthetic inner class constructor parameter
MethodInfo(it.returnType, it.typeParameters, it.valueParameterTypes.drop(1))
else -> it
}
}
val parameterTypes = info.valueParameterTypes
val paramCount = parameterTypes.size
val parameterList = parameterTypes.mapIndexed { i, type ->
val isEllipsisParam = isVarargs && i == paramCount - 1
BinaryJavaValueParameter(type, isEllipsisParam)
}
val member: BinaryJavaMethodBase =
if (isConstructor)
BinaryJavaConstructor(access, containingClass, parameterList, info.typeParameters)
else
BinaryJavaMethod(
access, containingClass,
parameterList,
info.typeParameters,
Name.identifier(name), info.returnType
)
val paramIgnoreCount = when {
isEnumConstructor -> 2
isInnerClassConstructor -> 1
else -> 0
}
return member to
AnnotationsAndParameterCollectorMethodVisitor(
member,
parentContext,
signatureParser,
paramIgnoreCount,
Type.getArgumentTypes(desc).size
)
}
private fun parseMethodDescription(
desc: String,
context: ClassifierResolutionContext,
signatureParser: BinaryClassSignatureParser
): MethodInfo {
val returnType = signatureParser.mapAsmType(Type.getReturnType(desc), context)
val parameterTypes = Type.getArgumentTypes(desc).map { signatureParser.mapAsmType(it, context) }
return MethodInfo(returnType, emptyList(), parameterTypes)
}
private fun parseMethodSignature(
signature: String,
signatureParser: BinaryClassSignatureParser,
context: ClassifierResolutionContext
): MethodInfo {
val iterator = StringCharacterIterator(signature)
val typeParameters = signatureParser.parseTypeParametersDeclaration(iterator, context)
if (iterator.current() != '(') throw ClsFormatException()
iterator.next()
var paramTypes: List<JavaType>
if (iterator.current() == ')') {
paramTypes = emptyList()
}
else {
paramTypes = mutableListOf()
while (iterator.current() != ')' && iterator.current() != CharacterIterator.DONE) {
paramTypes.add(signatureParser.parseTypeString(iterator, context))
}
if (iterator.current() != ')') throw ClsFormatException()
paramTypes = (paramTypes as ArrayList).compact()
}
iterator.next()
val returnType = signatureParser.parseTypeString(iterator, context)
return MethodInfo(returnType, typeParameters, paramTypes)
}
}
}
class BinaryJavaMethod(
flags: Int,
containingClass: JavaClass,
valueParameters: List<BinaryJavaValueParameter>,
typeParameters: List<JavaTypeParameter>,
name: Name,
override val returnType: JavaType
) : BinaryJavaMethodBase(
flags, containingClass, valueParameters, typeParameters, name
), JavaMethod {
override var annotationParameterDefaultValue: JavaAnnotationArgument? = null
internal set(value) {
if (field != null) {
throw AssertionError(
"Annotation method cannot have two default values: $this (old=$field, new=$value)"
)
}
field = value
}
}
class BinaryJavaConstructor(
flags: Int,
containingClass: JavaClass,
valueParameters: List<BinaryJavaValueParameter>,
typeParameters: List<JavaTypeParameter>
) : BinaryJavaMethodBase(
flags, containingClass, valueParameters, typeParameters,
SpecialNames.NO_NAME_PROVIDED
), JavaConstructor
@@ -1,93 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.org.objectweb.asm.ClassReader
import org.jetbrains.org.objectweb.asm.ClassVisitor
class BinaryJavaField(
override val name: Name,
override val access: Int,
override val containingClass: JavaClass,
override val isEnumEntry: Boolean,
override val type: JavaType,
override val initializerValue: Any?
) : JavaField, MapBasedJavaAnnotationOwner, BinaryJavaModifierListOwner {
override val annotations: MutableCollection<JavaAnnotation> = SmartList()
override val annotationsByFqName by buildLazyValueForMap()
override val hasConstantNotNullInitializer: Boolean
get() = initializerValue != null
}
class BinaryJavaTypeParameter(
override val name: Name,
override val upperBounds: Collection<JavaClassifierType>
) : JavaTypeParameter {
// TODO: support annotations on type parameters
override val annotations get() = emptyList<JavaAnnotation>()
override fun findAnnotation(fqName: FqName) = null
override val isDeprecatedInJavaDoc get() = false
}
class BinaryJavaValueParameter(
override val type: JavaType,
override val isVararg: Boolean
) : JavaValueParameter, MapBasedJavaAnnotationOwner {
override val annotations: MutableCollection<JavaAnnotation> = SmartList()
override val annotationsByFqName by buildLazyValueForMap()
override var name: Name? = null
internal fun updateName(newName: Name) {
assert(name == null) { "Parameter can't have two names: $name and $newName" }
name = newName
}
}
fun isNotTopLevelClass(classContent: ByteArray): Boolean {
var isNotTopLevelClass = false
ClassReader(classContent).accept(
object : ClassVisitor(ASM_API_VERSION_FOR_CLASS_READING) {
private var internalName: String? = null
override fun visit(
version: Int,
access: Int,
name: String?,
signature: String?,
superName: String?,
interfaces: Array<out String>?
) {
internalName = name
}
override fun visitInnerClass(name: String?, outerName: String?, innerName: String?, access: Int) {
// Do not read InnerClasses attribute values where full name != outer + $ + inner; treat those classes as top level instead.
if (name == internalName && (innerName == null || name == "$outerName$$innerName")) {
isNotTopLevelClass = true
}
}
},
ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES
)
return isNotTopLevelClass
}
@@ -1,64 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.utils.SmartList
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
// They are only used for java class files, but potentially may be used in other cases
// It would be better to call them like JavaSomeTypeImpl, but these names are already occupied by the PSI based types
internal class PlainJavaArrayType(override val componentType: JavaType) : JavaArrayType
internal class PlainJavaWildcardType(override val bound: JavaType?, override val isExtends: Boolean) : JavaWildcardType
internal class PlainJavaPrimitiveType(override val type: PrimitiveType?) : JavaPrimitiveType
internal class PlainJavaClassifierType(
// calculation of classifier and canonicalText
classifierComputation: () -> ClassifierResolutionContext.Result,
override val typeArguments: List<JavaType>
) : JavaClassifierType {
private val classifierResolverResult by lazy(LazyThreadSafetyMode.NONE, classifierComputation)
override val classifier get() = classifierResolverResult.classifier
override val isRaw
get() = typeArguments.isEmpty() &&
classifierResolverResult.classifier?.safeAs<JavaClass>()?.typeParameters?.isNotEmpty() == true
private var _annotations = emptyList<JavaAnnotation>()
override val annotations get() = _annotations
override fun findAnnotation(fqName: FqName) = annotations.find { it.classId?.asSingleFqName() == fqName }
internal fun addAnnotation(annotation: JavaAnnotation) {
if (_annotations.isEmpty()) {
_annotations = SmartList()
}
(_annotations as MutableList).add(annotation)
}
override val isDeprecatedInJavaDoc get() = false
override val classifierQualifiedName: String
get() = classifierResolverResult.qualifiedName
// TODO: render arguments for presentable text
override val presentableText: String
get() = classifierQualifiedName
}
@@ -1,48 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl.classFiles
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.descriptors.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.structure.JavaModifierListOwner
import org.jetbrains.kotlin.load.java.structure.MapBasedJavaAnnotationOwner
import org.jetbrains.org.objectweb.asm.Opcodes
internal const val ASM_API_VERSION_FOR_CLASS_READING = Opcodes.API_VERSION
internal interface BinaryJavaModifierListOwner : JavaModifierListOwner, MapBasedJavaAnnotationOwner {
val access: Int
fun isSet(flag: Int) = access.isSet(flag)
override val isAbstract get() = isSet(Opcodes.ACC_ABSTRACT)
override val isStatic get() = isSet(Opcodes.ACC_STATIC)
override val isFinal get() = isSet(Opcodes.ACC_FINAL)
override val visibility: Visibility
get() = when {
isSet(Opcodes.ACC_PRIVATE) -> Visibilities.Private
isSet(Opcodes.ACC_PROTECTED) ->
if (isStatic) JavaVisibilities.ProtectedStaticVisibility else JavaVisibilities.ProtectedAndPackage
isSet(Opcodes.ACC_PUBLIC) -> Visibilities.Public
else -> JavaVisibilities.PackageVisibility
}
override val isDeprecatedInJavaDoc get() = isSet(Opcodes.ACC_DEPRECATED)
}
internal fun Int.isSet(flag: Int) = this and flag != 0
@@ -1,43 +0,0 @@
/*
* Copyright 2010-2017 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.kotlin.load.java.structure.impl
import org.jetbrains.kotlin.name.SpecialNames
fun String.convertCanonicalNameToQName() = splitCanonicalFqName().joinToString(separator = ".") { it.substringBefore('<') }
// "test.A<B.C>.D<E<F.G, H>, I.J>" -> ["test", "A<B.C>", "D<E<F.G, H>, I.J>"]
private fun String.splitCanonicalFqName(): List<String> {
fun String.toNonEmpty(): String =
if (this.isNotEmpty()) this else SpecialNames.SAFE_IDENTIFIER_FOR_NO_NAME.asString()
val result = arrayListOf<String>()
var balance = 0
var currentNameStart = 0
for ((index, character) in this.withIndex()) {
when (character) {
'.' -> if (balance == 0) {
result.add(this.substring(currentNameStart, index).toNonEmpty())
currentNameStart = index + 1
}
'<' -> balance++
'>' -> balance--
}
}
result.add(this.substring(currentNameStart).toNonEmpty())
return result
}
@@ -28,11 +28,11 @@ import java.io.FileNotFoundException
import java.io.IOException
class VirtualFileKotlinClass private constructor(
val file: VirtualFile,
className: ClassId,
classVersion: Int,
classHeader: KotlinClassHeader,
innerClasses: InnerClassesInfo
val file: VirtualFile,
className: ClassId,
classVersion: Int,
classHeader: KotlinClassHeader,
innerClasses: InnerClassesInfo
) : FileBasedKotlinClass(className, classVersion, classHeader, innerClasses) {
override val location: String
@@ -1,28 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.resolve.jvm
import com.intellij.psi.impl.file.impl.JavaFileManager
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.load.java.JavaClassFinder
import org.jetbrains.kotlin.load.java.structure.JavaClass
import org.jetbrains.kotlin.name.FqName
interface KotlinCliJavaFileManager : JavaFileManager {
fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass?
fun knownClassNamesInPackage(packageFqName: FqName): Set<String>?
}
@@ -1,20 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.resolve.jvm;
public interface KotlinFinderMarker {
}
@@ -1,424 +0,0 @@
/*
* Copyright 2010-2015 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.kotlin.resolve.jvm;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.DumbAware;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.PackageIndex;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiElementFinderImpl;
import com.intellij.psi.impl.file.PsiPackageImpl;
import com.intellij.psi.impl.file.impl.JavaFileManager;
import com.intellij.psi.impl.light.LightModifierList;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiModificationTracker;
import com.intellij.reference.SoftReference;
import com.intellij.util.CommonProcessors;
import com.intellij.util.ConcurrencyUtil;
import com.intellij.util.Query;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.messages.MessageBus;
import kotlin.collections.ArraysKt;
import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.asJava.KtLightClassMarker;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.load.java.JavaClassFinder;
import org.jetbrains.kotlin.load.java.structure.JavaClass;
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl;
import org.jetbrains.kotlin.name.ClassId;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
public class KotlinJavaPsiFacade {
private volatile KotlinPsiElementFinderWrapper[] elementFinders;
private static class PackageCache {
final ConcurrentMap<Pair<String, GlobalSearchScope>, PsiPackage> packageInScopeCache = ContainerUtil.newConcurrentMap();
final ConcurrentMap<String, Boolean> hasPackageInAllScopeCache = ContainerUtil.newConcurrentMap();
}
private volatile SoftReference<PackageCache> packageCache;
private final Project project;
private final LightModifierList emptyModifierList;
public static KotlinJavaPsiFacade getInstance(Project project) {
return ServiceManager.getService(project, KotlinJavaPsiFacade.class);
}
public KotlinJavaPsiFacade(@NotNull Project project) {
this.project = project;
emptyModifierList = new LightModifierList(PsiManager.getInstance(project), KotlinLanguage.INSTANCE);
PsiModificationTracker modificationTracker = PsiManager.getInstance(project).getModificationTracker();
MessageBus bus = project.getMessageBus();
bus.connect().subscribe(PsiModificationTracker.TOPIC, new PsiModificationTracker.Listener() {
private long lastTimeSeen = -1L;
@Override
@SuppressWarnings("deprecation")
public void modificationCountChanged() {
long now = modificationTracker.getJavaStructureModificationCount();
if (lastTimeSeen != now) {
lastTimeSeen = now;
packageCache = null;
}
}
});
}
public void clearPackageCaches() {
packageCache = null;
}
public LightModifierList getEmptyModifierList() {
return emptyModifierList;
}
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly
ClassId classId = request.getClassId();
String qualifiedName = classId.asSingleFqName().asString();
if (shouldUseSlowResolve()) {
PsiClass[] classes = findClassesInDumbMode(qualifiedName, scope);
if (classes.length != 0) {
return createJavaClass(classId, classes[0]);
}
return null;
}
for (KotlinPsiElementFinderWrapper finder : finders()) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
if (finder instanceof CliFinder) {
JavaClass aClass = ((CliFinder) finder).findClass(request, scope);
if (aClass != null) return aClass;
}
else {
PsiClass aClass = finder.findClass(qualifiedName, scope);
if (aClass != null) return createJavaClass(classId, aClass);
}
}
return null;
}
@NotNull
private static JavaClass createJavaClass(@NotNull ClassId classId, @NotNull PsiClass psiClass) {
JavaClassImpl javaClass = new JavaClassImpl(psiClass);
FqName fqName = classId.asSingleFqName();
if (!fqName.equals(javaClass.getFqName())) {
throw new IllegalStateException("Requested " + fqName + ", got " + javaClass.getFqName());
}
if (psiClass instanceof KtLightClassMarker) {
throw new IllegalStateException("Kotlin light classes should not be found by JavaPsiFacade, resolving: " + fqName);
}
return javaClass;
}
@Nullable
public Set<String> knownClassNamesInPackage(@NotNull FqName packageFqName) {
KotlinPsiElementFinderWrapper[] finders = finders();
if (finders.length == 1 && finders[0] instanceof CliFinder) {
return ((CliFinder) finders[0]).knownClassNamesInPackage(packageFqName);
}
return null;
}
@NotNull
private PsiClass[] findClassesInDumbMode(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
String packageName = StringUtil.getPackageName(qualifiedName);
PsiPackage pkg = findPackage(packageName, scope);
String className = StringUtil.getShortName(qualifiedName);
if (pkg == null && packageName.length() < qualifiedName.length()) {
PsiClass[] containingClasses = findClassesInDumbMode(packageName, scope);
if (containingClasses.length == 1) {
return PsiElementFinder.filterByName(className, containingClasses[0].getInnerClasses());
}
return PsiClass.EMPTY_ARRAY;
}
if (pkg == null || !pkg.containsClassNamed(className)) {
return PsiClass.EMPTY_ARRAY;
}
return pkg.findClassByShortName(className, scope);
}
private boolean shouldUseSlowResolve() {
DumbService dumbService = DumbService.getInstance(getProject());
return dumbService.isDumb() && dumbService.isAlternativeResolveEnabled();
}
@NotNull
private KotlinPsiElementFinderWrapper[] finders() {
KotlinPsiElementFinderWrapper[] answer = elementFinders;
if (answer == null) {
answer = calcFinders();
elementFinders = answer;
}
return answer;
}
@NotNull
private KotlinPsiElementFinderWrapper[] calcFinders() {
List<KotlinPsiElementFinderWrapper> elementFinders = new ArrayList<>();
JavaFileManager javaFileManager = findJavaFileManager(project);
elementFinders.add(
javaFileManager instanceof KotlinCliJavaFileManager
? new CliFinder((KotlinCliJavaFileManager) javaFileManager)
: new NonCliFinder(project, javaFileManager)
);
List<PsiElementFinder> nonKotlinFinders = ArraysKt.filter(
getProject().getExtensions(PsiElementFinder.EP_NAME),
finder -> (finder instanceof KotlinSafeClassFinder) ||
!(finder instanceof NonClasspathClassFinder ||
finder instanceof KotlinFinderMarker ||
finder instanceof PsiElementFinderImpl)
);
elementFinders.addAll(CollectionsKt.map(nonKotlinFinders, KotlinJavaPsiFacade::wrap));
return elementFinders.toArray(new KotlinPsiElementFinderWrapper[elementFinders.size()]);
}
@NotNull
private static JavaFileManager findJavaFileManager(@NotNull Project project) {
JavaFileManager javaFileManager = ServiceManager.getService(project, JavaFileManager.class);
if (javaFileManager == null) {
throw new IllegalStateException("JavaFileManager component is not found in project");
}
return javaFileManager;
}
public PsiPackage findPackage(@NotNull String qualifiedName, GlobalSearchScope searchScope) {
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled();
PackageCache cache = SoftReference.dereference(packageCache);
if (cache == null) {
packageCache = new SoftReference<>(cache = new PackageCache());
}
Pair<String, GlobalSearchScope> key = new Pair<>(qualifiedName, searchScope);
PsiPackage aPackage = cache.packageInScopeCache.get(key);
if (aPackage != null) {
return aPackage;
}
KotlinPsiElementFinderWrapper[] finders = filteredFinders();
Boolean packageFoundInAllScope = cache.hasPackageInAllScopeCache.get(qualifiedName);
if (packageFoundInAllScope != null) {
if (!packageFoundInAllScope.booleanValue()) return null;
// Package was found in AllScope with some of finders but is absent in packageCache for current scope.
// We check only finders that depend on scope.
for (KotlinPsiElementFinderWrapper finder : finders) {
if (!finder.isSameResultForAnyScope()) {
aPackage = finder.findPackage(qualifiedName, searchScope);
if (aPackage != null) {
return ConcurrencyUtil.cacheOrGet(cache.packageInScopeCache, key, aPackage);
}
}
}
}
else {
for (KotlinPsiElementFinderWrapper finder : finders) {
aPackage = finder.findPackage(qualifiedName, searchScope);
if (aPackage != null) {
return ConcurrencyUtil.cacheOrGet(cache.packageInScopeCache, key, aPackage);
}
}
boolean found = false;
for (KotlinPsiElementFinderWrapper finder : finders) {
if (!finder.isSameResultForAnyScope()) {
aPackage = finder.findPackage(qualifiedName, GlobalSearchScope.allScope(project));
if (aPackage != null) {
found = true;
break;
}
}
}
cache.hasPackageInAllScopeCache.put(qualifiedName, found);
}
return null;
}
@NotNull
private KotlinPsiElementFinderWrapper[] filteredFinders() {
DumbService dumbService = DumbService.getInstance(getProject());
KotlinPsiElementFinderWrapper[] finders = finders();
if (dumbService.isDumb()) {
List<KotlinPsiElementFinderWrapper> list = dumbService.filterByDumbAwareness(Arrays.asList(finders));
finders = list.toArray(new KotlinPsiElementFinderWrapper[list.size()]);
}
return finders;
}
@NotNull
public Project getProject() {
return project;
}
public static KotlinPsiElementFinderWrapper wrap(PsiElementFinder finder) {
return finder instanceof DumbAware
? new KotlinPsiElementFinderWrapperImplDumbAware(finder)
: new KotlinPsiElementFinderWrapperImpl(finder);
}
interface KotlinPsiElementFinderWrapper {
PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope);
boolean isSameResultForAnyScope();
}
private static class KotlinPsiElementFinderWrapperImpl implements KotlinPsiElementFinderWrapper {
private final PsiElementFinder finder;
private KotlinPsiElementFinderWrapperImpl(@NotNull PsiElementFinder finder) {
this.finder = finder;
}
@Override
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
return finder.findClass(qualifiedName, scope);
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
// Original element finder can't search packages with scope
return finder.findPackage(qualifiedName);
}
@Override
public boolean isSameResultForAnyScope() {
return true;
}
@Override
public String toString() {
return finder.toString();
}
}
private static class KotlinPsiElementFinderWrapperImplDumbAware extends KotlinPsiElementFinderWrapperImpl implements DumbAware {
private KotlinPsiElementFinderWrapperImplDumbAware(PsiElementFinder finder) {
super(finder);
}
}
private static class CliFinder implements KotlinPsiElementFinderWrapper, DumbAware {
private final KotlinCliJavaFileManager javaFileManager;
public CliFinder(@NotNull KotlinCliJavaFileManager javaFileManager) {
this.javaFileManager = javaFileManager;
}
@Override
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
return javaFileManager.findClass(qualifiedName, scope);
}
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
return javaFileManager.findClass(request, scope);
}
@Nullable
public Set<String> knownClassNamesInPackage(@NotNull FqName packageFqName) {
return javaFileManager.knownClassNamesInPackage(packageFqName);
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
return javaFileManager.findPackage(qualifiedName);
}
@Override
public boolean isSameResultForAnyScope() {
return false;
}
}
private static class NonCliFinder implements KotlinPsiElementFinderWrapper, DumbAware {
private final JavaFileManager javaFileManager;
private final PsiManager psiManager;
private final PackageIndex packageIndex;
public NonCliFinder(@NotNull Project project, @NotNull JavaFileManager javaFileManager) {
this.javaFileManager = javaFileManager;
this.packageIndex = PackageIndex.getInstance(project);
this.psiManager = PsiManager.getInstance(project);
}
@Override
public PsiClass findClass(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
return javaFileManager.findClass(qualifiedName, scope);
}
@Override
public PsiPackage findPackage(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
Query<VirtualFile> dirs = packageIndex.getDirsByPackageName(qualifiedName, true);
return hasDirectoriesInScope(dirs, scope) ? new PsiPackageImpl(psiManager, qualifiedName) : null;
}
@Override
public boolean isSameResultForAnyScope() {
return false;
}
private static boolean hasDirectoriesInScope(Query<VirtualFile> dirs, GlobalSearchScope scope) {
CommonProcessors.FindProcessor<VirtualFile> findProcessor = new CommonProcessors.FindProcessor<VirtualFile>() {
@Override
protected boolean accept(VirtualFile file) {
return scope.accept(file);
}
};
dirs.forEach(findProcessor);
return findProcessor.isFound();
}
}
}
@@ -1,19 +0,0 @@
/*
* Copyright 2010-2016 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.kotlin.resolve.jvm
interface KotlinSafeClassFinder