Move common jvm classes from :core:descriptors.jvm to :core:compiler.common.jvm
This commit is contained in:
@@ -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
|
||||
}
|
||||
-97
@@ -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);
|
||||
}
|
||||
}
|
||||
-26
@@ -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();
|
||||
}
|
||||
-33
@@ -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());
|
||||
}
|
||||
}
|
||||
-138
@@ -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)
|
||||
}
|
||||
}
|
||||
-60
@@ -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();
|
||||
}
|
||||
}
|
||||
-105
@@ -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()
|
||||
}
|
||||
}
|
||||
-49
@@ -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());
|
||||
}
|
||||
}
|
||||
-84
@@ -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)
|
||||
}
|
||||
-49
@@ -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();
|
||||
}
|
||||
}
|
||||
-109
@@ -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;
|
||||
}
|
||||
}
|
||||
-56
@@ -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());
|
||||
}
|
||||
}
|
||||
-100
@@ -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();
|
||||
}
|
||||
}
|
||||
-85
@@ -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);
|
||||
}
|
||||
}
|
||||
-26
@@ -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();
|
||||
}
|
||||
-47
@@ -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()
|
||||
}
|
||||
-37
@@ -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();
|
||||
}
|
||||
}
|
||||
-112
@@ -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();
|
||||
}
|
||||
}
|
||||
-54
@@ -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();
|
||||
}
|
||||
}
|
||||
-106
@@ -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();
|
||||
}
|
||||
}
|
||||
-41
@@ -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();
|
||||
}
|
||||
}
|
||||
-27
@@ -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
|
||||
}
|
||||
-97
@@ -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)
|
||||
}
|
||||
-260
@@ -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)
|
||||
}
|
||||
-224
@@ -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)
|
||||
}
|
||||
-221
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
-122
@@ -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
|
||||
}
|
||||
}
|
||||
-188
@@ -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
|
||||
-93
@@ -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
|
||||
}
|
||||
-64
@@ -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
|
||||
}
|
||||
-48
@@ -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
|
||||
-43
@@ -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
|
||||
}
|
||||
+5
-5
@@ -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
|
||||
|
||||
-28
@@ -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
|
||||
Reference in New Issue
Block a user