Compare commits

...

27 Commits

Author SHA1 Message Date
Ilya Kirillov
3b97f4091b FIR IDE: remove unneeded dependencies of idea-fir & idea-frontend-fir modules 2020-05-29 15:49:50 +03:00
Ilya Kirillov
9472481c44 FIR IDE: ignore not passing highlighting tests 2020-05-29 15:49:50 +03:00
Ilya Kirillov
d50cfa7457 FIR IDE: improve search of containing declaration for getOrBuildFir 2020-05-29 15:49:50 +03:00
Ilya Kirillov
ca8ef7dcff FIR IDE: remove checker/duplicateJvmSignature tests for FIR as duplicate signature is not implemented for fir ide yet 2020-05-29 15:49:50 +03:00
Ilya Kirillov
f4bbfde3ad FIR IDE: Remove IGNORE_FIR from passing tests 2020-05-29 15:49:50 +03:00
Ilya Kirillov
8d3a41f650 FIR IDE: Fix tests in idea-fir 2020-05-29 15:49:49 +03:00
Ilya Kirillov
1a4fc777dc FIR IDE: Introduce plugin.xml for fir ide 2020-05-29 15:49:49 +03:00
Ilya Kirillov
7dfeb680f1 Fix idea.xml 2020-05-29 15:49:49 +03:00
Ilya Kirillov
b4a21beeaa FIR IDE: Move ApplicationUtils to frontend independent module 2020-05-29 15:49:49 +03:00
Ilya Kirillov
8fe8a554f0 FIR IDE: Introduce ide-frontend-independent.xml extensions 2020-05-29 15:49:48 +03:00
Ilya Kirillov
81025fae5a FIR IDE: Move common caches related stuff from plugin-common.xml to caches.xml 2020-05-29 15:49:45 +03:00
Ilya Kirillov
865a0096ee FIR IDE: Split resources to three folders which is needed for FIR plugin
The "resources" is common for both plugins,
 while resources-descriptors & resources-fir belongs
 to corresponding plugins
2020-05-29 15:49:31 +03:00
Ilya Kirillov
2598e63a0e FIR IDE: Move idea related stuff from plugin-common.xml to idea.xml 2020-05-29 15:49:27 +03:00
Ilya Kirillov
6ef870ce5a FIR IDE: Move jps related stuff from plugin-common.xml to jps.xml 2020-05-29 15:49:09 +03:00
Ilya Kirillov
b5434163e1 FIR IDE: Move index related stuff from plugin-common.xml to indexes.xml 2020-05-29 15:18:25 +03:00
Ilya Kirillov
deadd75003 FIR IDE: Move inspections from plugin-common.xml to inspections.xml 2020-05-29 15:18:25 +03:00
Ilya Kirillov
558f77e1e1 FIR IDE: Implement FIR reference resolve for some kinds of references
* implement for:
   * KtForLoopInReference
   * KtInvokeFunctionReference
   * KtPropertyDelegationMethodsReference
   * KtDestructuringDeclarationReference
2020-05-29 15:18:25 +03:00
Ilya Kirillov
da477eca36 FIR IDE: Implement search of psi elements for deserialized Kotlin declarations
Fix "FIR IDE: Implement search of psi elements for deserialized Kotlin declarations"
2020-05-29 15:18:24 +03:00
Ilya Kirillov
e910ef1c28 FIR IDE: Move some declarations highlighting to before resolve highlighting pass 2020-05-29 15:18:24 +03:00
Ilya Kirillov
5934c94040 FIR: do not assign PSI source of labeled expression to its typeRef 2020-05-29 15:18:24 +03:00
Ilya Kirillov
b9bc8b0e34 FIR IDE: Begin implementing semantic highlighting via FIR
* Introduce frontend api module & implement api for FIR
* Implement some basic declaration highlighting for FIR
2020-05-29 15:18:24 +03:00
Ilya Kirillov
4e11ab64c1 FIR: fix incorrect psi for named & spread arguments in FIR builder 2020-05-29 15:18:23 +03:00
Ilya Kirillov
622fba5210 FIR IDE: Move base part of highlighting to frontend-independent-module 2020-05-29 15:18:23 +03:00
Ilya Kirillov
527ecc9251 FIR IDE: Move KDoc Reference & mainReference to frontend-independent module 2020-05-29 15:18:23 +03:00
Ilya Kirillov
2cf682cda0 FIR IDE: Move fir resolving functionality from idea module to idea-frontend-fir 2020-05-29 15:18:23 +03:00
Ilya Kirillov
f7aeda41b3 FIR IDE: Start IDEA FIR plugin 2020-05-29 15:18:22 +03:00
Ilya Kirillov
90ab774646 FIR IDE: Make KtReference class descriptors frontend independent
* The new idea-frontend-independent module created
* Moved KtReference and it inheritors to that module & implement them in idea-analysis module by using descriptors frontend
2020-05-29 15:18:22 +03:00
201 changed files with 6467 additions and 4000 deletions

9
.idea/misc.xml generated
View File

@@ -12,6 +12,7 @@
<item index="2" class="java.lang.String" itemvalue="org.gradle.api.tasks.options.Option" />
</list>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
@@ -88,6 +89,14 @@
<option name="autoscroll" value="false" />
<option name="showOnlyWarnings" value="false" />
</component>
<component name="idea.plugin.psiviewer.controller.project.PsiViewerProjectService">
<option name="HIGHLIGHT" value="false" />
<option name="FILTER_WHITESPACE" value="true" />
<option name="SHOW_PROPERTIES" value="true" />
<option name="SPLIT_DIVIDER_POSITION" value="300" />
<option name="AUTOSCROLL_TO_SOURCE" value="true" />
<option name="AUTOSCROLL_FROM_SOURCE" value="false" />
</component>
<component name="intellij-api-watcher-check-current-project">
<option name="shouldCheckCurrentProject" value="true" />
</component>

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -85,7 +85,7 @@ class FirJavaModuleBasedSession(
class FirLibrarySession private constructor(
moduleInfo: ModuleInfo,
sessionProvider: FirProjectSessionProvider,
scope: GlobalSearchScope,
val scope: GlobalSearchScope,
packagePartProvider: PackagePartProvider,
kotlinClassFinder: KotlinClassFinder,
javaClassFinder: JavaClassFinder

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -67,6 +67,10 @@ class RawFirBuilder(
return file.accept(Visitor(), Unit) as FirFile
}
fun buildTypeReference(reference: KtTypeReference): FirTypeRef {
return reference.accept(Visitor(), Unit) as FirTypeRef
}
override fun PsiElement.toFirSourceElement(): FirPsiSourceElement<*> {
return this.toFirPsiSourceElement()
}
@@ -249,13 +253,13 @@ class RawFirBuilder(
val isSpread = getSpreadElement() != null
return when {
name != null -> buildNamedArgumentExpression {
source = expression?.toFirSourceElement()
source = (this@toFirExpression as? PsiElement)?.toFirSourceElement()
this.expression = firExpression
this.isSpread = isSpread
this.name = name
}
isSpread -> buildSpreadArgumentExpression {
source = expression?.toFirSourceElement()
source = (this@toFirExpression as? PsiElement)?.toFirSourceElement()
this.expression = firExpression
}
else -> firExpression

View File

@@ -24,7 +24,7 @@ internal class FirBreakExpressionImpl(
override val annotations: MutableList<FirAnnotationCall>,
override val target: FirTarget<FirLoop>,
) : FirBreakExpression() {
override var typeRef: FirTypeRef = FirImplicitNothingTypeRef(source)
override var typeRef: FirTypeRef = FirImplicitNothingTypeRef(null)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
typeRef.accept(visitor, data)

View File

@@ -24,7 +24,7 @@ internal class FirContinueExpressionImpl(
override val annotations: MutableList<FirAnnotationCall>,
override val target: FirTarget<FirLoop>,
) : FirContinueExpression() {
override var typeRef: FirTypeRef = FirImplicitNothingTypeRef(source)
override var typeRef: FirTypeRef = FirImplicitNothingTypeRef(null)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
typeRef.accept(visitor, data)

View File

@@ -26,7 +26,7 @@ internal class FirReturnExpressionImpl(
override val target: FirTarget<FirFunction<*>>,
override var result: FirExpression,
) : FirReturnExpression() {
override var typeRef: FirTypeRef = FirImplicitNothingTypeRef(source)
override var typeRef: FirTypeRef = FirImplicitNothingTypeRef(null)
override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {
typeRef.accept(visitor, data)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -243,7 +243,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
impl(resolvedReifiedParameterReference)
impl(returnExpression) {
default("typeRef", "FirImplicitNothingTypeRef(source)")
default("typeRef", "FirImplicitNothingTypeRef(null)")
useTypes(implicitNothingTypeRefType)
}
@@ -425,12 +425,12 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
}
impl(breakExpression) {
default("typeRef", "FirImplicitNothingTypeRef(source)")
default("typeRef", "FirImplicitNothingTypeRef(null)")
useTypes(implicitNothingTypeRefType)
}
impl(continueExpression) {
default("typeRef", "FirImplicitNothingTypeRef(source)")
default("typeRef", "FirImplicitNothingTypeRef(null)")
useTypes(implicitNothingTypeRefType)
}

View File

@@ -0,0 +1,24 @@
/*
* 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.resolve
import org.jetbrains.kotlin.builtins.PrimitiveType
import org.jetbrains.kotlin.name.Name
object ArrayFqNames {
val PRIMITIVE_TYPE_TO_ARRAY: Map<PrimitiveType, Name> = hashMapOf(
PrimitiveType.BOOLEAN to Name.identifier("booleanArrayOf"),
PrimitiveType.CHAR to Name.identifier("charArrayOf"),
PrimitiveType.INT to Name.identifier("intArrayOf"),
PrimitiveType.BYTE to Name.identifier("byteArrayOf"),
PrimitiveType.SHORT to Name.identifier("shortArrayOf"),
PrimitiveType.FLOAT to Name.identifier("floatArrayOf"),
PrimitiveType.LONG to Name.identifier("longArrayOf"),
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
)
val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
}

View File

@@ -1,17 +1,6 @@
/*
* 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.
* 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.resolve
@@ -44,21 +33,6 @@ class CollectionLiteralResolver(
val callResolver: CallResolver,
val languageVersionSettings: LanguageVersionSettings
) {
companion object {
val PRIMITIVE_TYPE_TO_ARRAY: Map<PrimitiveType, Name> = hashMapOf(
PrimitiveType.BOOLEAN to Name.identifier("booleanArrayOf"),
PrimitiveType.CHAR to Name.identifier("charArrayOf"),
PrimitiveType.INT to Name.identifier("intArrayOf"),
PrimitiveType.BYTE to Name.identifier("byteArrayOf"),
PrimitiveType.SHORT to Name.identifier("shortArrayOf"),
PrimitiveType.FLOAT to Name.identifier("floatArrayOf"),
PrimitiveType.LONG to Name.identifier("longArrayOf"),
PrimitiveType.DOUBLE to Name.identifier("doubleArrayOf")
)
val ARRAY_OF_FUNCTION = Name.identifier("arrayOf")
}
fun resolveCollectionLiteral(
collectionLiteralExpression: KtCollectionLiteralExpression,
context: ExpressionTypingContext
@@ -120,11 +94,11 @@ class CollectionLiteralResolver(
private fun getArrayFunctionCallName(expectedType: KotlinType): Name {
if (NO_EXPECTED_TYPE === expectedType || !KotlinBuiltIns.isPrimitiveArray(expectedType)) {
return ARRAY_OF_FUNCTION
return ArrayFqNames.ARRAY_OF_FUNCTION
}
val descriptor = expectedType.constructor.declarationDescriptor ?: return ARRAY_OF_FUNCTION
val descriptor = expectedType.constructor.declarationDescriptor ?: return ArrayFqNames.ARRAY_OF_FUNCTION
return PRIMITIVE_TYPE_TO_ARRAY[KotlinBuiltIns.getPrimitiveArrayType(descriptor)] ?: ARRAY_OF_FUNCTION
return ArrayFqNames.PRIMITIVE_TYPE_TO_ARRAY[KotlinBuiltIns.getPrimitiveArrayType(descriptor)] ?: ArrayFqNames.ARRAY_OF_FUNCTION
}
}

View File

@@ -1,17 +1,6 @@
/*
* 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.
* 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.utils.addToStdlib
@@ -50,6 +39,17 @@ inline fun <reified T> Array<*>.firstIsInstance(): T {
throw NoSuchElementException("No element of given type found")
}
inline fun <reified T> Iterable<*>.filterIsInstanceWithChecker(additionalChecker: (T) -> Boolean): List<T> {
val result = arrayListOf<T>()
for (element in this) {
if (element is T && additionalChecker(element)) {
result += element
}
}
return result
}
inline fun <reified T : Any> Iterable<*>.lastIsInstanceOrNull(): T? {
when (this) {
is List<*> -> {

View File

@@ -38,6 +38,7 @@ dependencies {
testCompile(projectTests(":compiler:cli"))
testCompile(projectTests(":idea:idea-maven"))
testCompile(projectTests(":idea:idea-fir"))
testCompile(projectTests(":idea:idea-frontend-fir"))
testCompile(projectTests(":j2k"))
testCompile(projectTests(":nj2k"))
if (Ide.IJ()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -84,6 +84,7 @@ import org.jetbrains.kotlin.idea.editor.quickDoc.AbstractQuickDocProviderTest
import org.jetbrains.kotlin.idea.filters.AbstractKotlinExceptionFilterTest
import org.jetbrains.kotlin.idea.fir.AbstractFirLazyResolveTest
import org.jetbrains.kotlin.idea.fir.AbstractFirMultiModuleResolveTest
import org.jetbrains.kotlin.idea.fir.AbstractKtDeclarationAndFirDeclarationEqualityChecker
import org.jetbrains.kotlin.idea.folding.AbstractKotlinFoldingTest
import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyTest
import org.jetbrains.kotlin.idea.hierarchy.AbstractHierarchyWithLibTest
@@ -904,11 +905,21 @@ fun main() {
}
}
testGroup("idea/idea-frontend-fir/tests", "idea/idea-frontend-fir/testData") {
testClass<AbstractKtDeclarationAndFirDeclarationEqualityChecker> {
model("ktDeclarationAndFirDeclarationEqualityChecker")
}
}
testGroup("idea/idea-fir/tests", "idea/testData") {
testClass<AbstractFirMultiModuleResolveTest> {
model("fir/multiModule", recursive = false, extension = null)
}
testClass<AbstractFirHighlightingTest> {
model("highlighter")
}
testClass<AbstractFirLazyResolveTest> {
model("fir/lazyResolve", extension = "test", singleClass = true, filenameStartsLowerCase = true)
}
@@ -922,7 +933,6 @@ fun main() {
model("checker/regression")
model("checker/recovery")
model("checker/rendering")
model("checker/duplicateJvmSignature")
model("checker/infos")
model("checker/diagnosticsMessage")
}

View File

@@ -6,6 +6,9 @@ plugins {
}
val kotlinVersion: String by rootProject.extra
val isFirPlugin: Boolean
get() = rootProject.findProperty("idea.fir.plugin") == "true"
repositories {
maven("https://jetbrains.bintray.com/markdown")
@@ -25,6 +28,11 @@ sourceSets {
"idea-repl/resources",
"resources-en"
)
if (isFirPlugin) {
resources.srcDir("resources-fir")
} else {
resources.srcDir("resources-descriptors")
}
}
"test" {
projectDefault()
@@ -71,6 +79,7 @@ dependencies {
compile(project(":compiler:fir:java"))
compile(project(":compiler:fir:jvm"))
compile(project(":idea:idea-core"))
compile(project(":idea:idea-frontend-independent"))
compile(project(":idea:ide-common"))
compile(project(":idea:idea-jps-common"))
compile(project(":idea:kotlin-gradle-tooling"))

View File

@@ -10,14 +10,11 @@ import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.lang.annotation.Annotation
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.util.TextRange
import com.intellij.util.containers.MultiMap
import com.intellij.xml.util.XmlStringUtil
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
class AnnotationPresentationInfo(
@@ -52,55 +49,14 @@ class AnnotationPresentationInfo(
}
}
private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation {
val defaultMessage = nonDefaultMessage ?: getDefaultMessage(diagnostic)
val annotation = when (diagnostic.severity) {
Severity.ERROR -> holder.createErrorAnnotation(range, defaultMessage)
Severity.WARNING -> {
if (highlightType == ProblemHighlightType.WEAK_WARNING) {
holder.createWeakWarningAnnotation(range, defaultMessage)
} else {
holder.createWarningAnnotation(range, defaultMessage)
}
}
Severity.INFO -> holder.createInfoAnnotation(range, defaultMessage)
}
annotation.tooltip = getMessage(diagnostic)
if (highlightType != null) {
annotation.highlightType = highlightType
}
if (textAttributes != null) {
annotation.textAttributes = textAttributes
}
return annotation
}
private fun getMessage(diagnostic: Diagnostic): String {
var message = IdeErrorMessages.render(diagnostic)
if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
val factoryName = diagnostic.factory.name
message = if (message.startsWith("<html>")) {
"<html>[$factoryName] ${message.substring("<html>".length)}"
} else {
"[$factoryName] $message"
}
}
if (!message.startsWith("<html>")) {
message = "<html><body>${XmlStringUtil.escapeString(message)}</body></html>"
}
return message
}
private fun getDefaultMessage(diagnostic: Diagnostic): String {
val message = DefaultErrorMessages.render(diagnostic)
if (ApplicationManager.getApplication().isInternal || ApplicationManager.getApplication().isUnitTestMode) {
return "[${diagnostic.factory.name}] $message"
}
return message
}
private fun create(diagnostic: Diagnostic, range: TextRange, holder: AnnotationHolder): Annotation =
Diagnostic2Annotation.createAnnotation(
diagnostic,
range,
holder,
nonDefaultMessage,
textAttributes,
highlightType,
IdeErrorMessages::render
)
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -28,21 +28,6 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
internal class FunctionsHighlightingVisitor(holder: AnnotationHolder, bindingContext: BindingContext) :
AfterAnalysisHighlightingVisitor(holder, bindingContext) {
override fun visitNamedFunction(function: KtNamedFunction) {
function.nameIdentifier?.let { highlightName(it, FUNCTION_DECLARATION) }
super.visitNamedFunction(function)
}
override fun visitSuperTypeCallEntry(call: KtSuperTypeCallEntry) {
val calleeExpression = call.calleeExpression
val typeElement = calleeExpression.typeReference?.typeElement
if (typeElement is KtUserType) {
typeElement.referenceExpression?.let { highlightName(it, CONSTRUCTOR_CALL) }
}
super.visitSuperTypeCallEntry(call)
}
override fun visitBinaryExpression(expression: KtBinaryExpression) {
if (expression.operationReference.getIdentifier() != null) {
val resolvedCall = expression.getResolvedCall(bindingContext)

View File

@@ -1,26 +1,13 @@
/*
* 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.
* 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.idea.highlighter
import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.openapi.diagnostic.ControlFlowException
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.colors.CodeInsightColors
@@ -28,7 +15,6 @@ import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.util.Key
import com.intellij.psi.MultiRangeReference
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
@@ -38,35 +24,23 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.caches.resolve.analyzeWithAllCompilerChecks
import org.jetbrains.kotlin.idea.fir.FirResolution
import org.jetbrains.kotlin.idea.fir.firResolveState
import org.jetbrains.kotlin.idea.fir.getOrBuildFirWithDiagnostics
import org.jetbrains.kotlin.idea.quickfix.QuickFixes
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.util.module
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import java.lang.reflect.*
import java.util.*
open class KotlinPsiChecker : Annotator, HighlightRangeExtension {
open class KotlinPsiChecker : AbstractKotlinPsiChecker() {
override fun shouldHighlight(file: KtFile): Boolean = KotlinHighlightingUtil.shouldHighlight(file)
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
val file = element.containingFile as? KtFile ?: return
if (!KotlinHighlightingUtil.shouldHighlight(file)) return
if (FirResolution.enabled) {
annotateElementUsingFrontendIR(element, file, holder)
} else {
annotateElement(element, file, holder)
}
}
private fun annotateElement(
override fun annotateElement(
element: PsiElement,
containingFile: KtFile,
holder: AnnotationHolder
@@ -83,29 +57,6 @@ open class KotlinPsiChecker : Annotator, HighlightRangeExtension {
annotateElement(element, holder, bindingContext.diagnostics)
}
private fun annotateElementUsingFrontendIR(
element: PsiElement,
containingFile: KtFile,
holder: AnnotationHolder
) {
if (element !is KtElement) return
val state = containingFile.firResolveState()
containingFile.getOrBuildFirWithDiagnostics(state)
val diagnostics = state.getDiagnostics(element)
if (diagnostics.isEmpty()) return
if (KotlinHighlightingUtil.shouldHighlightErrors(element)) {
ElementAnnotator(element, holder) { param ->
shouldSuppressUnusedParameter(param)
}.registerDiagnosticsAnnotations(diagnostics)
}
}
override fun isForceHighlightParents(file: PsiFile): Boolean {
return file is KtFile
}
protected open fun shouldSuppressUnusedParameter(parameter: KtParameter): Boolean = false
fun annotateElement(element: PsiElement, holder: AnnotationHolder, diagnostics: Diagnostics) {

View File

@@ -1,25 +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.idea.highlighter
import org.jetbrains.annotations.TestOnly
object NameHighlighter {
var namesHighlightingEnabled = true
@TestOnly set
}

View File

@@ -1,17 +1,6 @@
/*
* 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.
* 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.idea.highlighter
@@ -92,11 +81,6 @@ internal class TypeKindHighlightingVisitor(holder: AnnotationHolder, bindingCont
return TextRange(atSymbol.textRange.startOffset, expression.textRange.endOffset)
}
override fun visitTypeParameter(parameter: KtTypeParameter) {
parameter.nameIdentifier?.let { highlightName(it, TYPE_PARAMETER) }
super.visitTypeParameter(parameter)
}
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
val identifier = classOrObject.nameIdentifier
val classDescriptor = bindingContext.get(BindingContext.CLASS, classOrObject)

View File

@@ -1,17 +1,6 @@
/*
* 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.
* 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.idea.kdoc
@@ -20,6 +9,8 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.references.KDocReference
import org.jetbrains.kotlin.idea.references.KtDescriptorsBasedReference
import org.jetbrains.kotlin.idea.references.KtMultiReference
import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
import org.jetbrains.kotlin.kdoc.psi.impl.KDocName
@@ -28,7 +19,10 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class KDocReference(element: KDocName) : KtMultiReference<KDocName>(element) {
class KDocReferenceDescriptorsImpl(element: KDocName) : KDocReference(element), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val declaration = element.getContainingDoc().getOwner() ?: return arrayListOf()
val resolutionFacade = element.getResolutionFacade()
@@ -45,20 +39,10 @@ class KDocReference(element: KDocName) : KtMultiReference<KDocName>(element) {
)
}
override fun getRangeInElement(): TextRange = element.getNameTextRange()
override fun canRename(): Boolean = true
override fun resolve(): PsiElement? = multiResolve(false).firstOrNull()?.element
override fun handleElementRename(newElementName: String): PsiElement? {
val textRange = element.getNameTextRange()
val newText = textRange.replace(element.text, newElementName)
val newLink = KDocElementFactory(element.project).createNameFromText(newText)
return element.replace(newLink)
}
override fun getCanonicalText(): String = element.getNameText()
override val resolvesByNames: Collection<Name> get() = listOf(Name.identifier(element.getNameText()))
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -66,14 +66,10 @@ class ReferenceImpl(private val argument: KtValueArgument) : PsiReference {
override fun isSoft() = false
}
internal class KotlinDefaultAnnotationMethodImplicitReferenceContributor : KotlinReferenceProviderContributor {
override fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar) {
registrar.registerProvider<KtValueArgument> {
if (it.isNamed()) return@registerProvider null
val annotationEntry = it.getParentOfTypeAndBranch<KtAnnotationEntry> { valueArgumentList } ?: return@registerProvider null
if (annotationEntry.valueArguments.size != 1) return@registerProvider null
internal val KotlinDefaultAnnotationMethodImplicitReferenceProvider = provider@{ element: KtValueArgument ->
if (element.isNamed()) return@provider null
val annotationEntry = element.getParentOfTypeAndBranch<KtAnnotationEntry> { valueArgumentList } ?: return@provider null
if (annotationEntry.valueArguments.size != 1) return@provider null
ReferenceImpl(it)
}
}
}
ReferenceImpl(element)
}

View File

@@ -1,22 +1,11 @@
/*
* 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.
* 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.idea.references
import org.jetbrains.kotlin.idea.kdoc.KDocReference
import org.jetbrains.kotlin.idea.kdoc.KDocReferenceDescriptorsImpl
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
@@ -24,10 +13,10 @@ import org.jetbrains.kotlin.psi.KtPackageDirective
import org.jetbrains.kotlin.psi.KtUserType
import org.jetbrains.kotlin.psi.psiUtil.parents
internal class KotlinReferenceContributor : KotlinReferenceProviderContributor {
class KotlinReferenceContributor : KotlinReferenceProviderContributor {
override fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar) {
with(registrar) {
registerProvider(factory = ::KtSimpleNameReference)
registerProvider(factory = ::KtSimpleNameReferenceDescriptorsImpl)
registerMultiProvider<KtNameReferenceExpression> { nameReferenceExpression ->
if (nameReferenceExpression.getReferencedNameElementType() != KtTokens.IDENTIFIER) return@registerMultiProvider emptyArray()
@@ -37,32 +26,34 @@ internal class KotlinReferenceContributor : KotlinReferenceProviderContributor {
when (nameReferenceExpression.readWriteAccess(useResolveForReadWrite = false)) {
ReferenceAccess.READ ->
arrayOf(SyntheticPropertyAccessorReference.Getter(nameReferenceExpression))
arrayOf(SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = true))
ReferenceAccess.WRITE ->
arrayOf(SyntheticPropertyAccessorReference.Setter(nameReferenceExpression))
arrayOf(SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = false))
ReferenceAccess.READ_WRITE ->
arrayOf(
SyntheticPropertyAccessorReference.Getter(nameReferenceExpression),
SyntheticPropertyAccessorReference.Setter(nameReferenceExpression)
SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = true),
SyntheticPropertyAccessorReferenceDescriptorImpl(nameReferenceExpression, getter = false)
)
}
}
registerProvider(factory = ::KtConstructorDelegationReference)
registerProvider(factory = ::KtConstructorDelegationReferenceDescriptorsImpl)
registerProvider(factory = ::KtInvokeFunctionReference)
registerProvider(factory = ::KtInvokeFunctionReferenceDescriptorsImpl)
registerProvider(factory = ::KtArrayAccessReference)
registerProvider(factory = ::KtArrayAccessReferenceDescriptorsImpl)
registerProvider(factory = ::KtCollectionLiteralReference)
registerProvider(factory = ::KtCollectionLiteralReferenceDescriptorsImpl)
registerProvider(factory = ::KtForLoopInReference)
registerProvider(factory = ::KtForLoopInReferenceDescriptorsImpl)
registerProvider(factory = ::KtPropertyDelegationMethodsReference)
registerProvider(factory = ::KtPropertyDelegationMethodsReferenceDescriptorsImpl)
registerProvider(factory = ::KtDestructuringDeclarationReference)
registerProvider(factory = ::KtDestructuringDeclarationReferenceDescriptorsImpl)
registerProvider(factory = ::KDocReference)
registerProvider(factory = ::KDocReferenceDescriptorsImpl)
registerProvider(KotlinDefaultAnnotationMethodImplicitReferenceProvider)
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.idea.references
import com.intellij.psi.MultiRangeReference
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.idea.core.canMoveLambdaOutsideParentheses
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_GET
import org.jetbrains.kotlin.resolve.BindingContext.INDEXED_LVALUE_SET
internal class KtArrayAccessReferenceDescriptorsImpl(
expression: KtArrayAccessExpression
) : KtArrayAccessReference(expression), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun moveFunctionLiteralOutsideParentheses(callExpression: KtCallExpression) {
callExpression.moveFunctionLiteralOutsideParentheses()
}
override fun canMoveLambdaOutsideParentheses(callExpression: KtCallExpression): Boolean =
callExpression.canMoveLambdaOutsideParentheses()
override fun doRenameImplicitConventionalCall(newName: String?): KtExpression =
renameImplicitConventionalCall(newName)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val getFunctionDescriptor = context[INDEXED_LVALUE_GET, expression]?.candidateDescriptor
val setFunctionDescriptor = context[INDEXED_LVALUE_SET, expression]?.candidateDescriptor
return listOfNotNull(getFunctionDescriptor, setFunctionDescriptor)
}
}

View File

@@ -0,0 +1,23 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.KtCollectionLiteralExpression
import org.jetbrains.kotlin.resolve.BindingContext
class KtCollectionLiteralReferenceDescriptorsImpl(
expression: KtCollectionLiteralExpression
) : KtCollectionLiteralReference(expression), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val resolvedCall = context[BindingContext.COLLECTION_LITERAL_CALL, element]
return listOfNotNull(resolvedCall?.resultingDescriptor)
}
}

View File

@@ -1,51 +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.idea.references;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression;
import java.util.Collection;
import java.util.Collections;
public class KtConstructorDelegationReference extends KtSimpleReference<KtConstructorDelegationReferenceExpression> {
public KtConstructorDelegationReference(KtConstructorDelegationReferenceExpression expression) {
super(expression);
}
@Override
public TextRange getRangeInElement() {
return new TextRange(0, getElement().getTextLength());
}
@NotNull
@Override
public Collection<Name> getResolvesByNames() {
return Collections.emptyList();
}
@Nullable
@Override
public PsiElement handleElementRename(@Nullable String newElementName) {
// Class rename never affects this reference, so there is no need to fail with exception
return getExpression();
}
}

View File

@@ -0,0 +1,20 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtConstructorDelegationReferenceExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
class KtConstructorDelegationReferenceDescriptorsImpl(
expression: KtConstructorDelegationReferenceExpression
) : KtConstructorDelegationReference(expression), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun getTargetDescriptors(context: BindingContext) = expression.getReferenceTargets(context)
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -16,8 +16,12 @@ import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
import org.jetbrains.kotlin.resolve.BindingContext
class KtDestructuringDeclarationReference(element: KtDestructuringDeclarationEntry) :
AbstractKtReference<KtDestructuringDeclarationEntry>(element) {
class KtDestructuringDeclarationReferenceDescriptorsImpl(
element: KtDestructuringDeclarationEntry
) : KtDestructuringDeclarationReference(element), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
return listOfNotNull(context[BindingContext.COMPONENT_RESOLVED_CALL, element]?.candidateDescriptor)
}
@@ -30,16 +34,4 @@ class KtDestructuringDeclarationReference(element: KtDestructuringDeclarationEnt
it is CallableMemberDescriptor && it.kind == CallableMemberDescriptor.Kind.SYNTHESIZED
}
}
override fun handleElementRename(newElementName: String): PsiElement? {
if (canRename()) return expression
throw IncorrectOperationException()
}
override val resolvesByNames: Collection<Name>
get() {
val destructuringParent = element.parent as? KtDestructuringDeclaration ?: return emptyList()
val componentIndex = destructuringParent.entries.indexOf(element) + 1
return listOf(Name.identifier("component$componentIndex"))
}
}

View File

@@ -1,45 +1,34 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.util.OperatorNameConventions
class KtForLoopInReference(element: KtForExpression) : KtMultiReference<KtForExpression>(element) {
override fun getRangeInElement(): TextRange {
val inKeyword = expression.inKeyword ?: return TextRange.EMPTY_RANGE
val offset = inKeyword.startOffsetInParent
return TextRange(offset, offset + inKeyword.textLength)
}
class KtForLoopInReferenceDescriptorsImpl(
element: KtForExpression
) : KtForLoopInReference(element), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val loopRange = expression.loopRange ?: return emptyList()
return LOOP_RANGE_KEYS.mapNotNull { key -> context.get(key, loopRange)?.candidateDescriptor }
}
override val resolvesByNames: Collection<Name>
get() = NAMES
companion object {
private val LOOP_RANGE_KEYS = arrayOf(
BindingContext.LOOP_RANGE_ITERATOR_RESOLVED_CALL,
BindingContext.LOOP_RANGE_NEXT_RESOLVED_CALL,
BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL
)
private val NAMES = listOf(
OperatorNameConventions.ITERATOR,
OperatorNameConventions.NEXT,
OperatorNameConventions.HAS_NEXT
)
}
}

View File

@@ -0,0 +1,38 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.psi.Call
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getCall
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall
class KtInvokeFunctionReferenceDescriptorsImpl(expression: KtCallExpression) : KtInvokeFunctionReference(expression), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val call = element.getCall(context)
val resolvedCall = call.getResolvedCall(context)
return when {
resolvedCall is VariableAsFunctionResolvedCall ->
setOf<DeclarationDescriptor>((resolvedCall as VariableAsFunctionResolvedCall).functionCall.candidateDescriptor)
call != null && resolvedCall != null && call.callType == Call.CallType.INVOKE ->
setOf<DeclarationDescriptor>(resolvedCall.candidateDescriptor)
else ->
emptyList()
}
}
override fun doRenameImplicitConventionalCall(newName: String?): KtExpression =
renameImplicitConventionalCall(newName)
}

View File

@@ -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.idea.references
import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.descriptors.accessors
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyDelegate
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.util.OperatorNameConventions
class KtPropertyDelegationMethodsReference(element: KtPropertyDelegate) : KtMultiReference<KtPropertyDelegate>(element) {
override fun getRangeInElement(): TextRange {
val byKeywordNode = expression.byKeywordNode
val offset = byKeywordNode.psi!!.startOffsetInParent
return TextRange(offset, offset + byKeywordNode.textLength)
}
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val property = expression.getStrictParentOfType<KtProperty>() ?: return emptyList()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? VariableDescriptorWithAccessors
?: return emptyList()
return (descriptor.accessors.mapNotNull { accessor ->
context.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor)?.candidateDescriptor
} + listOfNotNull(context.get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, descriptor)?.candidateDescriptor))
}
override val resolvesByNames: Collection<Name> get() = NAMES
companion object {
private val NAMES = listOf(
OperatorNameConventions.GET_VALUE,
OperatorNameConventions.SET_VALUE,
OperatorNameConventions.PROVIDE_DELEGATE
)
}
}

View File

@@ -0,0 +1,31 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.descriptors.accessors
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyDelegate
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
class KtPropertyDelegationMethodsReferenceDescriptorsImpl(
element: KtPropertyDelegate
) : KtPropertyDelegationMethodsReference(element), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<KtDescriptorsBasedReference>.isReferenceTo(element)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val property = expression.getStrictParentOfType<KtProperty>() ?: return emptyList()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, property] as? VariableDescriptorWithAccessors
?: return emptyList()
return descriptor.accessors.mapNotNull { accessor ->
context.get(BindingContext.DELEGATED_PROPERTY_RESOLVED_CALL, accessor)?.candidateDescriptor
} + listOfNotNull(context.get(BindingContext.PROVIDE_DELEGATE_RESOLVED_CALL, descriptor)?.candidateDescriptor)
}
}

View File

@@ -1,17 +1,6 @@
/*
* 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.
* 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.idea.references
@@ -35,9 +24,6 @@ import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.fir.FirResolution
import org.jetbrains.kotlin.idea.fir.firResolveState
import org.jetbrains.kotlin.idea.fir.getOrBuildFir
import org.jetbrains.kotlin.idea.util.application.runWithCancellationCheck
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
@@ -51,251 +37,79 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import java.util.*
interface KtReference : PsiPolyVariantReference {
fun resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor>
interface KtDescriptorsBasedReference : KtReference {
override val resolver get() = KotlinDescriptorsBasedReferenceResolver
override fun getElement(): KtElement
val resolvesByNames: Collection<Name>
}
abstract class AbstractKtReference<T : KtElement>(element: T) : PsiPolyVariantReferenceBase<T>(element), KtReference {
val expression: T
get() = element
override fun multiResolve(incompleteCode: Boolean): Array<ResolveResult> {
@Suppress("UNCHECKED_CAST")
val kotlinResolver = KOTLIN_RESOLVER as ResolveCache.PolyVariantResolver<AbstractKtReference<T>>
return ResolveCache.getInstance(expression.project).resolveWithCaching(this, kotlinResolver, false, incompleteCode)
fun resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
return getTargetDescriptors(bindingContext)
}
fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor>
override fun isReferenceTo(element: PsiElement): Boolean {
return matchesTarget(element)
}
override fun getCanonicalText(): String = "<TBD>"
open fun canRename(): Boolean = false
override fun handleElementRename(newElementName: String): PsiElement? = throw IncorrectOperationException()
override fun bindToElement(element: PsiElement): PsiElement = throw IncorrectOperationException()
@Suppress("UNCHECKED_CAST")
override fun getVariants(): Array<Any> = PsiReference.EMPTY_ARRAY as Array<Any>
override fun isSoft(): Boolean = false
override fun resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
return getTargetDescriptors(bindingContext)
}
protected abstract fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor>
override fun toString() = this::class.java.simpleName + ": " + expression.text
companion object {
private object FirReferenceResolveHelper {
fun FirResolvedTypeRef.toTargetPsi(session: FirSession): PsiElement? {
val type = type as? ConeLookupTagBasedType ?: return null
return (type.lookupTag.toSymbol(session) as? AbstractFirBasedSymbol<*>)?.fir?.psi
}
fun ClassId.toTargetPsi(session: FirSession, calleeReference: FirReference? = null): PsiElement? {
val classLikeDeclaration = ConeClassLikeLookupTagImpl(this).toSymbol(session)?.fir
if (classLikeDeclaration is FirRegularClass) {
if (calleeReference is FirResolvedNamedReference) {
val callee = calleeReference.resolvedSymbol.fir as? FirCallableMemberDeclaration
// TODO: check callee owner directly?
if (callee !is FirConstructor && callee?.isStatic != true) {
classLikeDeclaration.companionObject?.let { return it.psi }
}
}
}
return classLikeDeclaration?.psi
}
fun FirReference.toTargetPsi(session: FirSession): PsiElement? {
return when (this) {
is FirResolvedNamedReference -> {
resolvedSymbol.fir.psi
}
is FirResolvedCallableReference -> {
resolvedSymbol.fir.psi
}
is FirThisReference -> {
boundSymbol?.fir?.psi
}
is FirSuperReference -> {
(superTypeRef as? FirResolvedTypeRef)?.toTargetPsi(session)
}
else -> {
null
}
}
}
fun resolveToPsiElements(ref: AbstractKtReference<KtElement>): Collection<PsiElement> {
val expression = ref.expression
val state = expression.firResolveState()
val session = state.getSession(expression)
when (val fir = expression.getOrBuildFir(state)) {
is FirResolvable -> {
return listOfNotNull(fir.calleeReference.toTargetPsi(session))
}
is FirResolvedTypeRef -> {
return listOfNotNull(fir.toTargetPsi(session))
}
is FirResolvedQualifier -> {
val classId = fir.classId ?: return emptyList()
// Distinguish A.foo() from A(.Companion).foo()
// Make expression.parent as? KtDotQualifiedExpression local function
var parent = expression.parent as? KtDotQualifiedExpression
while (parent != null) {
val selectorExpression = parent.selectorExpression ?: break
if (selectorExpression === expression) {
parent = parent.parent as? KtDotQualifiedExpression
continue
}
val parentFir = selectorExpression.getOrBuildFir(state)
if (parentFir is FirQualifiedAccess) {
return listOfNotNull(classId.toTargetPsi(session, parentFir.calleeReference))
}
parent = parent.parent as? KtDotQualifiedExpression
}
return listOfNotNull(classId.toTargetPsi(session))
}
is FirAnnotationCall -> {
val type = fir.typeRef as? FirResolvedTypeRef ?: return emptyList()
return listOfNotNull(type.toTargetPsi(session))
}
is FirResolvedImport -> {
var parent = expression.parent
while (parent is KtDotQualifiedExpression) {
if (parent.selectorExpression !== expression) {
// Special: package reference in the middle of import directive
// import a.<caret>b.c.SomeClass
// TODO: return reference to PsiPackage
return listOf(expression)
}
parent = parent.parent
}
val classId = fir.resolvedClassId
if (classId != null) {
return listOfNotNull(classId.toTargetPsi(session))
}
val name = fir.importedName ?: return emptyList()
val symbolProvider = session.firSymbolProvider
return symbolProvider.getTopLevelCallableSymbols(fir.packageFqName, name).mapNotNull { it.fir.psi } +
listOfNotNull(symbolProvider.getClassLikeSymbolByFqName(ClassId(fir.packageFqName, name))?.fir?.psi)
}
is FirFile -> {
if (expression.getNonStrictParentOfType<KtPackageDirective>() != null) {
// Special: package reference in the middle of package directive
return listOf(expression)
}
return listOfNotNull(fir.psi)
}
is FirArrayOfCall -> {
// We can't yet find PsiElement for arrayOf, intArrayOf, etc.
return emptyList()
}
is FirErrorNamedReference -> {
return emptyList()
}
else -> {
// Handle situation when we're in the middle/beginning of qualifier
// <caret>A.B.C.foo() or A.<caret>B.C.foo()
// NB: in this case we get some parent FIR, like FirBlock, FirProperty, FirFunction or the like
var parent = expression.parent as? KtDotQualifiedExpression
var unresolvedCounter = 1
while (parent != null) {
val selectorExpression = parent.selectorExpression ?: break
if (selectorExpression === expression) {
parent = parent.parent as? KtDotQualifiedExpression
continue
}
val parentFir = selectorExpression.getOrBuildFir(state)
if (parentFir is FirResolvedQualifier) {
var classId = parentFir.classId
while (unresolvedCounter > 0) {
unresolvedCounter--
classId = classId?.outerClassId
}
return listOfNotNull(classId?.toTargetPsi(session))
}
parent = parent.parent as? KtDotQualifiedExpression
unresolvedCounter++
}
return emptyList()
}
}
}
}
class KotlinReferenceResolver : ResolveCache.PolyVariantResolver<AbstractKtReference<KtElement>> {
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
private fun resolveToPsiElements(ref: AbstractKtReference<KtElement>): Collection<PsiElement> {
if (FirResolution.enabled) {
return FirReferenceResolveHelper.resolveToPsiElements(ref)
}
val bindingContext = ref.expression.analyze(BodyResolveMode.PARTIAL)
return resolveToPsiElements(ref, bindingContext, ref.getTargetDescriptors(bindingContext))
}
private fun resolveToPsiElements(
ref: AbstractKtReference<KtElement>,
context: BindingContext,
targetDescriptors: Collection<DeclarationDescriptor>
): Collection<PsiElement> {
if (targetDescriptors.isNotEmpty()) {
return targetDescriptors.flatMap { target -> resolveToPsiElements(ref, target) }.toSet()
}
val labelTargets = getLabelTargets(ref, context)
if (labelTargets != null) {
return labelTargets
}
return Collections.emptySet()
}
private fun resolveToPsiElements(
ref: AbstractKtReference<KtElement>,
targetDescriptor: DeclarationDescriptor
): Collection<PsiElement> {
return if (targetDescriptor is PackageViewDescriptor) {
val psiFacade = JavaPsiFacade.getInstance(ref.expression.project)
val fqName = targetDescriptor.fqName.asString()
listOfNotNull(psiFacade.findPackage(fqName))
} else {
DescriptorToSourceUtilsIde.getAllDeclarations(ref.expression.project, targetDescriptor, ref.expression.resolveScope)
}
}
private fun getLabelTargets(ref: AbstractKtReference<KtElement>, context: BindingContext): Collection<PsiElement>? {
val reference = ref.expression as? KtReferenceExpression ?: return null
val labelTarget = context[BindingContext.LABEL_TARGET, reference]
if (labelTarget != null) {
return listOf(labelTarget)
}
return context[BindingContext.AMBIGUOUS_LABEL_TARGET, reference]
}
override fun resolve(ref: AbstractKtReference<KtElement>, incompleteCode: Boolean): Array<ResolveResult> {
return runWithCancellationCheck {
val resolveToPsiElements = resolveToPsiElements(ref)
resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
}
}
}
val KOTLIN_RESOLVER = KotlinReferenceResolver()
}
}
abstract class KtSimpleReference<T : KtReferenceExpression>(expression: T) : AbstractKtReference<T>(expression) {
override fun getTargetDescriptors(context: BindingContext) = expression.getReferenceTargets(context)
fun KtReference.resolveToDescriptors(bindingContext: BindingContext): Collection<DeclarationDescriptor> {
if (this !is KtDescriptorsBasedReference) {
error("Reference $this should be KtDescriptorsBasedReference but was ${this::class}")
}
return resolveToDescriptors(bindingContext)
}
abstract class KtMultiReference<T : KtElement>(expression: T) : AbstractKtReference<T>(expression)
object KotlinDescriptorsBasedReferenceResolver : ResolveCache.PolyVariantResolver<KtReference> {
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
private fun resolveToPsiElements(ref: KtDescriptorsBasedReference): Collection<PsiElement> {
val bindingContext = ref.element.analyze(BodyResolveMode.PARTIAL)
return resolveToPsiElements(ref, bindingContext, ref.getTargetDescriptors(bindingContext))
}
private fun resolveToPsiElements(
ref: KtDescriptorsBasedReference,
context: BindingContext,
targetDescriptors: Collection<DeclarationDescriptor>
): Collection<PsiElement> {
if (targetDescriptors.isNotEmpty()) {
return targetDescriptors.flatMap { target -> resolveToPsiElements(ref, target) }.toSet()
}
val labelTargets = getLabelTargets(ref, context)
if (labelTargets != null) {
return labelTargets
}
return Collections.emptySet()
}
private fun resolveToPsiElements(
ref: KtDescriptorsBasedReference,
targetDescriptor: DeclarationDescriptor
): Collection<PsiElement> {
return if (targetDescriptor is PackageViewDescriptor) {
val psiFacade = JavaPsiFacade.getInstance(ref.element.project)
val fqName = targetDescriptor.fqName.asString()
listOfNotNull(psiFacade.findPackage(fqName))
} else {
DescriptorToSourceUtilsIde.getAllDeclarations(ref.element.project, targetDescriptor, ref.element.resolveScope)
}
}
private fun getLabelTargets(ref: KtDescriptorsBasedReference, context: BindingContext): Collection<PsiElement>? {
val reference = ref.element as? KtReferenceExpression ?: return null
val labelTarget = context[BindingContext.LABEL_TARGET, reference]
if (labelTarget != null) {
return listOf(labelTarget)
}
return context[BindingContext.AMBIGUOUS_LABEL_TARGET, reference]
}
override fun resolve(ref: KtReference, incompleteCode: Boolean): Array<ResolveResult> {
return runWithCancellationCheck {
val resolveToPsiElements = resolveToPsiElements(ref as KtDescriptorsBasedReference)
resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.references
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiReference
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.IncorrectOperationException
import com.intellij.util.SmartList
@@ -33,15 +34,24 @@ import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DataClassDescriptorResolver
import org.jetbrains.kotlin.resolve.ImportedFromObjectCallableDescriptor
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.expressions.OperatorConventions
class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleReference<KtSimpleNameExpression>(expression) {
class KtSimpleNameReferenceDescriptorsImpl(
expression: KtSimpleNameExpression
) : KtSimpleNameReference(expression), KtDescriptorsBasedReference {
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean =
canBeReferenceTo(candidateTarget)
override fun isReferenceToWithoutExtensionChecking(candidateTarget: PsiElement): Boolean =
matchesTarget(candidateTarget)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
return SmartList<DeclarationDescriptor>().apply {
// Replace Java property with its accessor(s)
for (descriptor in super.getTargetDescriptors(context)) {
for (descriptor in expression.getReferenceTargets(context)) {
val sizeBefore = size
if (descriptor !is JavaPropertyDescriptor) {
@@ -71,7 +81,7 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
if (extension.isReferenceTo(this, element)) return true
}
return super.isReferenceTo(element)
return super<KtDescriptorsBasedReference>.isReferenceTo(element)
}
override fun getRangeInElement(): TextRange {
@@ -141,23 +151,18 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
return expression
}
enum class ShorteningMode {
NO_SHORTENING,
DELAYED_SHORTENING,
FORCED_SHORTENING
}
// By default reference binding is delayed
override fun bindToElement(element: PsiElement): PsiElement =
bindToElement(element, ShorteningMode.DELAYED_SHORTENING)
fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement =
override fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement =
element.getKotlinFqName()?.let { fqName -> bindToFqName(fqName, shorteningMode, element) } ?: expression
fun bindToFqName(
override fun bindToFqName(
fqName: FqName,
shorteningMode: ShorteningMode = ShorteningMode.DELAYED_SHORTENING,
targetElement: PsiElement? = null
shorteningMode: ShorteningMode,
targetElement: PsiElement?
): PsiElement {
val expression = expression
if (fqName.isRoot) return expression
@@ -289,7 +294,7 @@ class KtSimpleNameReference(expression: KtSimpleNameExpression) : KtSimpleRefere
return listOf(element.getReferencedNameAsName())
}
fun getImportAlias(): KtImportAlias? {
override fun getImportAlias(): KtImportAlias? {
fun DeclarationDescriptor.unwrap() = if (this is ImportedFromObjectCallableDescriptor<*>) callableFromObject else this
val element = element

View File

@@ -0,0 +1,23 @@
/*
* 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.idea.references
import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.types.expressions.OperatorConventions
class ReadWriteAccessCheckerDescriptorsImpl : ReadWriteAccessChecker {
override fun readWriteAccessWithFullExpressionByResolve(assignment: KtBinaryExpression): Pair<ReferenceAccess, KtExpression> {
val resolvedCall = assignment.resolveToCall() ?: return ReferenceAccess.READ_WRITE to assignment
if (!resolvedCall.isReallySuccess()) return ReferenceAccess.READ_WRITE to assignment
return if (resolvedCall.resultingDescriptor.name in OperatorConventions.ASSIGNMENT_OPERATIONS.values)
ReferenceAccess.READ to assignment
else
ReferenceAccess.READ_WRITE to assignment
}
}

View File

@@ -1,13 +1,11 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.idea.references
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.util.SmartList
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
@@ -22,14 +20,22 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getReferenceTargets
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.utils.addIfNotNull
sealed class SyntheticPropertyAccessorReference(expression: KtNameReferenceExpression, private val getter: Boolean) :
KtSimpleReference<KtNameReferenceExpression>(expression) {
class SyntheticPropertyAccessorReferenceDescriptorImpl(
expression: KtNameReferenceExpression,
getter: Boolean
) : SyntheticPropertyAccessorReference(expression, getter), KtDescriptorsBasedReference {
override fun isReferenceTo(element: PsiElement): Boolean =
super<SyntheticPropertyAccessorReference>.isReferenceTo(element)
override fun additionalIsReferenceToChecker(element: PsiElement): Boolean = matchesTarget(element)
override fun getTargetDescriptors(context: BindingContext): Collection<DeclarationDescriptor> {
val descriptors = super.getTargetDescriptors(context)
val descriptors = expression.getReferenceTargets(context)
if (descriptors.none { it is SyntheticJavaPropertyDescriptor }) return emptyList()
val result = SmartList<FunctionDescriptor>()
@@ -45,23 +51,6 @@ sealed class SyntheticPropertyAccessorReference(expression: KtNameReferenceExpre
return result
}
override fun isReferenceTo(element: PsiElement): Boolean {
if (element !is PsiMethod || !isAccessorName(element.name)) return false
if (!getter && expression.readWriteAccess(true) == ReferenceAccess.READ) return false
return super.isReferenceTo(element)
}
private fun isAccessorName(name: String): Boolean {
if (getter) {
return name.startsWith("get") || name.startsWith("is")
}
return name.startsWith("set")
}
override fun getRangeInElement() = TextRange(0, expression.textLength)
override fun canRename() = true
private fun renameByPropertyName(newName: String): PsiElement? {
val nameIdentifier = KtPsiFactory(expression).createNameIdentifier(newName)
expression.getReferencedNameElement().replace(nameIdentifier)
@@ -183,7 +172,4 @@ sealed class SyntheticPropertyAccessorReference(expression: KtNameReferenceExpre
override val resolvesByNames: Collection<Name>
get() = listOf(element.getReferencedNameAsName())
class Getter(expression: KtNameReferenceExpression) : SyntheticPropertyAccessorReference(expression, true)
class Setter(expression: KtNameReferenceExpression) : SyntheticPropertyAccessorReference(expression, false)
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -17,7 +17,6 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveToCall
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention
import org.jetbrains.kotlin.idea.kdoc.KDocReference
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinFunctionShortNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinPropertyShortNameIndex
@@ -221,22 +220,6 @@ fun AbstractKtReference<out KtExpression>.renameImplicitConventionalCall(newName
return newExpression
}
val KtSimpleNameExpression.mainReference: KtSimpleNameReference
get() = references.firstIsInstance()
val KtReferenceExpression.mainReference: KtReference
get() = if (this is KtSimpleNameExpression) mainReference else references.firstIsInstance<KtReference>()
val KDocName.mainReference: KDocReference
get() = references.firstIsInstance()
val KtElement.mainReference: KtReference?
get() = when (this) {
is KtReferenceExpression -> mainReference
is KDocName -> mainReference
else -> references.firstIsInstanceOrNull<KtReference>()
}
fun KtElement.resolveMainReferenceToDescriptors(): Collection<DeclarationDescriptor> {
val bindingContext = analyze(BodyResolveMode.PARTIAL)
return mainReference?.resolveToDescriptors(bindingContext) ?: emptyList()
@@ -248,46 +231,6 @@ fun PsiReference.getImportAlias(): KtImportAlias? {
// ----------- Read/write access -----------------------------------------------------------------------------------------------------------------------
enum class ReferenceAccess(val isRead: Boolean, val isWrite: Boolean) {
READ(true, false), WRITE(false, true), READ_WRITE(true, true)
}
fun KtExpression.readWriteAccess(useResolveForReadWrite: Boolean) = readWriteAccessWithFullExpression(useResolveForReadWrite).first
fun KtExpression.readWriteAccessWithFullExpression(useResolveForReadWrite: Boolean): Pair<ReferenceAccess, KtExpression> {
var expression = getQualifiedExpressionForSelectorOrThis()
loop@ while (true) {
when (val parent = expression.parent) {
is KtParenthesizedExpression, is KtAnnotatedExpression, is KtLabeledExpression -> expression = parent as KtExpression
else -> break@loop
}
}
val assignment = expression.getAssignmentByLHS()
if (assignment != null) {
when (assignment.operationToken) {
KtTokens.EQ -> return ReferenceAccess.WRITE to assignment
else -> {
if (!useResolveForReadWrite) return ReferenceAccess.READ_WRITE to assignment
val resolvedCall = assignment.resolveToCall() ?: return ReferenceAccess.READ_WRITE to assignment
if (!resolvedCall.isReallySuccess()) return ReferenceAccess.READ_WRITE to assignment
return if (resolvedCall.resultingDescriptor.name in OperatorConventions.ASSIGNMENT_OPERATIONS.values)
ReferenceAccess.READ to assignment
else
ReferenceAccess.READ_WRITE to assignment
}
}
}
val unaryExpression = expression.parent as? KtUnaryExpression
return if (unaryExpression != null && unaryExpression.operationToken in constant { setOf(KtTokens.PLUSPLUS, KtTokens.MINUSMINUS) })
ReferenceAccess.READ_WRITE to unaryExpression
else
ReferenceAccess.READ to expression
}
fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor, bindingContext: BindingContext): Boolean {
if (this is KDocReference) {
val qualifier = element.getQualifier() ?: return true

View File

@@ -16,6 +16,7 @@ dependencies {
compile(project(":compiler:util"))
compile(project(":idea:ide-common"))
compile(project(":idea:idea-jps-common"))
compile(project(":idea:idea-frontend-independent"))
compile(project(":kotlin-util-klib-metadata"))
compile(project(":plugins:android-extensions-compiler"))
compile(project(":kotlin-scripting-compiler-impl"))

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
import org.jetbrains.kotlin.idea.imports.getImportableTargets
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveToDescriptors
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.psi.*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.idea.references.resolveToDescriptors
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getImplicitReceiversWithInstanceToExpression
@@ -158,8 +159,6 @@ fun KtCallableDeclaration.canOmitDeclaredType(initializerOrBodyExpression: KtExp
return canChangeTypeToSubtype && expressionType.isSubtypeOf(declaredType)
}
fun String.unquote(): String = KtPsiUtil.unquoteIdentifier(this)
fun FqName.quoteSegmentsIfNeeded(): String {
return pathSegments().joinToString(".") { it.asString().quoteIfNeeded() }
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -45,14 +45,6 @@ import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
import org.jetbrains.kotlin.utils.SmartList
inline fun <reified T : PsiElement> PsiElement.replaced(newElement: T): T {
val result = replace(newElement)
return result as? T ?: (result as KtParenthesizedExpression).expression as T
}
@Suppress("UNCHECKED_CAST")
fun <T : PsiElement> T.copied(): T = copy() as T
fun KtLambdaArgument.moveInsideParentheses(bindingContext: BindingContext): KtCallExpression {
val ktExpression = this.getArgumentExpression()
?: throw KotlinExceptionWithAttachments("no argument expression for $this")

View File

@@ -4,52 +4,26 @@ plugins {
}
dependencies {
testCompileOnly(toolsJar())
testRuntimeOnly(toolsJar())
compile(project(":idea:idea-frontend-fir"))
compile(project(":idea:formatter"))
compile(intellijDep())
compile(intellijCoreDep())
testRuntimeOnly(intellijPluginDep("gradle"))
testCompile(project(":idea"))
// <temp>
compile(project(":idea:idea-core"))
compile(project(":idea"))
// </temp>
testCompile(toolsJar())
testCompile(projectTests(":idea"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":idea:idea-test-framework")) { isTransitive = false }
testCompile(projectTests(":idea:idea-test-framework"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile(commonDep("junit:junit"))
testCompileOnly(intellijDep())
testRuntime(intellijDep())
if (Platform[191].orLower()) {
testRuntimeOnly(intellijPluginDep("Groovy"))
}
Platform[192].orHigher {
testCompileOnly(intellijPluginDep("java"))
testRuntime(intellijPluginDep("java"))
compile(intellijPluginDep("java"))
}
testRuntime(intellijRuntimeAnnotations())
testRuntime(project(":plugins:kapt3-idea")) { isTransitive = false }
testRuntime(project(":kotlin-reflect"))
testRuntime(project(":kotlin-preloader"))
testCompile(project(":kotlin-sam-with-receiver-compiler-plugin")) { isTransitive = false }
testRuntime(project(":plugins:android-extensions-compiler"))
testRuntimeOnly(project(":kotlin-android-extensions-runtime")) // TODO: fix import (workaround for jps build)
testRuntime(project(":plugins:android-extensions-ide")) { isTransitive = false }
testRuntime(project(":allopen-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlin-allopen-compiler-plugin"))
testRuntime(project(":noarg-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlin-noarg-compiler-plugin"))
testRuntime(project(":plugins:annotation-based-compiler-plugins-ide-support")) { isTransitive = false }
testRuntime(project(":kotlin-scripting-idea")) { isTransitive = false }
testRuntime(project(":kotlin-scripting-compiler-impl"))
testRuntime(project(":sam-with-receiver-ide-plugin")) { isTransitive = false }
testRuntime(project(":kotlinx-serialization-compiler-plugin"))
testRuntime(project(":kotlinx-serialization-ide-plugin")) { isTransitive = false }
testRuntime(project(":idea:idea-android")) { isTransitive = false }
testRuntime(project(":plugins:lint")) { isTransitive = false }
testRuntime(project(":plugins:uast-kotlin"))
testRuntime(project(":nj2k:nj2k-services")) { isTransitive = false }
}
sourceSets {
@@ -57,9 +31,11 @@ sourceSets {
"test" { projectDefault() }
}
projectTest(parallel = true) {
dependsOn(":dist")
workingDir = rootDir
if (rootProject.findProperty("idea.fir.plugin") == "true") {
projectTest(parallel = true) {
dependsOn(":dist")
workingDir = rootDir
}
}
testsJar()
testsJar()

View File

@@ -12,6 +12,8 @@ import org.jetbrains.kotlin.test.InTextDirectivesUtils
import java.io.File
abstract class AbstractFirPsiCheckerTest : AbstractPsiCheckerTest() {
override fun isFirPlugin(): Boolean = true
override fun setUp() {
super.setUp()
FirResolution.enabled = true

View File

@@ -650,118 +650,6 @@ public class FirPsiCheckerTestGenerated extends AbstractFirPsiCheckerTest {
}
}
@TestMetadata("idea/testData/checker/duplicateJvmSignature")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class DuplicateJvmSignature extends AbstractFirPsiCheckerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInDuplicateJvmSignature() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/checker/duplicateJvmSignature"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("idea/testData/checker/duplicateJvmSignature/fields")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Fields extends AbstractFirPsiCheckerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInFields() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/checker/duplicateJvmSignature/fields"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("classObjectCopiedFieldObject.kt")
public void testClassObjectCopiedFieldObject() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/fields/classObjectCopiedFieldObject.kt");
}
}
@TestMetadata("idea/testData/checker/duplicateJvmSignature/functionAndProperty")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class FunctionAndProperty extends AbstractFirPsiCheckerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInFunctionAndProperty() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/checker/duplicateJvmSignature/functionAndProperty"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("ambiguous.kt")
public void testAmbiguous() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/ambiguous.kt");
}
@TestMetadata("class.kt")
public void testClass() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/class.kt");
}
@TestMetadata("classObject.kt")
public void testClassObject() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/classObject.kt");
}
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/localClass.kt");
}
@TestMetadata("nestedClass.kt")
public void testNestedClass() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/nestedClass.kt");
}
@TestMetadata("object.kt")
public void testObject() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/object.kt");
}
@TestMetadata("objectExpression.kt")
public void testObjectExpression() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/objectExpression.kt");
}
@TestMetadata("topLevel.kt")
public void testTopLevel() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/topLevel.kt");
}
@TestMetadata("topLevelMultifileRuntime.kt")
public void testTopLevelMultifileRuntime() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/topLevelMultifileRuntime.kt");
}
@TestMetadata("trait.kt")
public void testTrait() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/functionAndProperty/trait.kt");
}
}
@TestMetadata("idea/testData/checker/duplicateJvmSignature/traitImpl")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class TraitImpl extends AbstractFirPsiCheckerTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInTraitImpl() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/checker/duplicateJvmSignature/traitImpl"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("twoTraits.kt")
public void testTwoTraits() throws Exception {
runTest("idea/testData/checker/duplicateJvmSignature/traitImpl/twoTraits.kt");
}
}
}
@TestMetadata("idea/testData/checker/infos")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)

View File

@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.idea.jsonUtils.getString
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
@@ -31,6 +30,8 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
import java.io.File
abstract class AbstractFirLazyResolveTest : KotlinLightCodeInsightFixtureTestCase() {
override fun isFirPlugin(): Boolean = true
override fun getProjectDescriptor(): LightProjectDescriptor {
if (KotlinTestUtils.isAllFilesPresentTest(getTestName(false))) return super.getProjectDescriptor()
val testFile = File(testDataPath, fileName())

View File

@@ -1,11 +1,13 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.idea.fir
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
@@ -47,7 +49,6 @@ import org.jetbrains.kotlin.idea.multiplatform.setupMppProjectFromDirStructure
import org.jetbrains.kotlin.idea.stubs.AbstractMultiModuleTest
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.TestJdkKind
@@ -202,3 +203,4 @@ abstract class AbstractFirMultiModuleResolveTest : AbstractMultiModuleTest() {
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.idea.fir
import org.jetbrains.kotlin.idea.AbstractResolveElementCacheTest
class FirResolveStateTest : AbstractResolveElementCacheTest() {
override fun isFirPlugin(): Boolean = true
fun testSimpleStateCaching() {
doTest {
val firstStatement = statements[0]

View File

@@ -0,0 +1,11 @@
/*
* 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.idea.fir
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
internal fun Project.allModules() = ModuleManager.getInstance(this).modules.toList()

View File

@@ -0,0 +1,31 @@
/*
* 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.idea.highlighter
import org.jetbrains.kotlin.idea.test.ProjectDescriptorWithStdlibSources
import org.jetbrains.kotlin.test.InTextDirectivesUtils
abstract class AbstractFirHighlightingTest : AbstractHighlightingTest() {
override fun getDefaultProjectDescriptor() = ProjectDescriptorWithStdlibSources.INSTANCE
override fun isFirPlugin() = true
override fun checkHighlighting(fileText: String) {
val doComparison = !InTextDirectivesUtils.isDirectiveDefined(myFixture.file.text, "IGNORE_FIR")
val checkInfos = !InTextDirectivesUtils.isDirectiveDefined(fileText, NO_CHECK_INFOS_PREFIX);
try {
// warnings are not supported yet
myFixture.checkHighlighting(/* checkWarnings= */ false, checkInfos, /* checkWeakWarnings= */ false)
} catch (e: Throwable) {
if (doComparison) throw e
return
}
if (!doComparison) {
throw AssertionError("Looks like test is passing, please remove IGNORE_FIR")
}
}
}

View File

@@ -0,0 +1,253 @@
/*
* 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.idea.highlighter;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/testData/highlighter")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class FirHighlightingTestGenerated extends AbstractFirHighlightingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInHighlighter() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/highlighter"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("Annotations.kt")
public void testAnnotations() throws Exception {
runTest("idea/testData/highlighter/Annotations.kt");
}
@TestMetadata("AutoCreatedItParameter.kt")
public void testAutoCreatedItParameter() throws Exception {
runTest("idea/testData/highlighter/AutoCreatedItParameter.kt");
}
@TestMetadata("Destructuring.kt")
public void testDestructuring() throws Exception {
runTest("idea/testData/highlighter/Destructuring.kt");
}
@TestMetadata("Dynamic.kt")
public void testDynamic() throws Exception {
runTest("idea/testData/highlighter/Dynamic.kt");
}
@TestMetadata("Enums.kt")
public void testEnums() throws Exception {
runTest("idea/testData/highlighter/Enums.kt");
}
@TestMetadata("Field.kt")
public void testField() throws Exception {
runTest("idea/testData/highlighter/Field.kt");
}
@TestMetadata("Functions.kt")
public void testFunctions() throws Exception {
runTest("idea/testData/highlighter/Functions.kt");
}
@TestMetadata("InvokeCall.kt")
public void testInvokeCall() throws Exception {
runTest("idea/testData/highlighter/InvokeCall.kt");
}
@TestMetadata("JavaTypes.kt")
public void testJavaTypes() throws Exception {
runTest("idea/testData/highlighter/JavaTypes.kt");
}
@TestMetadata("KDoc.kt")
public void testKDoc() throws Exception {
runTest("idea/testData/highlighter/KDoc.kt");
}
@TestMetadata("KotlinInjection.kt")
public void testKotlinInjection() throws Exception {
runTest("idea/testData/highlighter/KotlinInjection.kt");
}
@TestMetadata("Labels.kt")
public void testLabels() throws Exception {
runTest("idea/testData/highlighter/Labels.kt");
}
@TestMetadata("NamedArguments.kt")
public void testNamedArguments() throws Exception {
runTest("idea/testData/highlighter/NamedArguments.kt");
}
@TestMetadata("NonNullAssertion.kt")
public void testNonNullAssertion() throws Exception {
runTest("idea/testData/highlighter/NonNullAssertion.kt");
}
@TestMetadata("Object.kt")
public void testObject() throws Exception {
runTest("idea/testData/highlighter/Object.kt");
}
@TestMetadata("PropertiesWithPropertyDeclarations.kt")
public void testPropertiesWithPropertyDeclarations() throws Exception {
runTest("idea/testData/highlighter/PropertiesWithPropertyDeclarations.kt");
}
@TestMetadata("SmartCast.kt")
public void testSmartCast() throws Exception {
runTest("idea/testData/highlighter/SmartCast.kt");
}
@TestMetadata("Suspend.kt")
public void testSuspend() throws Exception {
runTest("idea/testData/highlighter/Suspend.kt");
}
@TestMetadata("SyntheticExtensionProperty.kt")
public void testSyntheticExtensionProperty() throws Exception {
runTest("idea/testData/highlighter/SyntheticExtensionProperty.kt");
}
@TestMetadata("Todo.kt")
public void testTodo() throws Exception {
runTest("idea/testData/highlighter/Todo.kt");
}
@TestMetadata("TopLevelDestructuring.kt")
public void testTopLevelDestructuring() throws Exception {
runTest("idea/testData/highlighter/TopLevelDestructuring.kt");
}
@TestMetadata("TopLevelOpenSuspendFun.kt")
public void testTopLevelOpenSuspendFun() throws Exception {
runTest("idea/testData/highlighter/TopLevelOpenSuspendFun.kt");
}
@TestMetadata("TypeAlias.kt")
public void testTypeAlias() throws Exception {
runTest("idea/testData/highlighter/TypeAlias.kt");
}
@TestMetadata("TypesAndAnnotations.kt")
public void testTypesAndAnnotations() throws Exception {
runTest("idea/testData/highlighter/TypesAndAnnotations.kt");
}
@TestMetadata("Variables.kt")
public void testVariables() throws Exception {
runTest("idea/testData/highlighter/Variables.kt");
}
@TestMetadata("VariablesAsFunctions.kt")
public void testVariablesAsFunctions() throws Exception {
runTest("idea/testData/highlighter/VariablesAsFunctions.kt");
}
@TestMetadata("idea/testData/highlighter/deprecated")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Deprecated extends AbstractFirHighlightingTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInDeprecated() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/highlighter/deprecated"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("Class.kt")
public void testClass() throws Exception {
runTest("idea/testData/highlighter/deprecated/Class.kt");
}
@TestMetadata("ClassObject.kt")
public void testClassObject() throws Exception {
runTest("idea/testData/highlighter/deprecated/ClassObject.kt");
}
@TestMetadata("Constructor.kt")
public void testConstructor() throws Exception {
runTest("idea/testData/highlighter/deprecated/Constructor.kt");
}
@TestMetadata("ExtensionFunction.kt")
public void testExtensionFunction() throws Exception {
runTest("idea/testData/highlighter/deprecated/ExtensionFunction.kt");
}
@TestMetadata("Function.kt")
public void testFunction() throws Exception {
runTest("idea/testData/highlighter/deprecated/Function.kt");
}
@TestMetadata("Get.kt")
public void testGet() throws Exception {
runTest("idea/testData/highlighter/deprecated/Get.kt");
}
@TestMetadata("Getter.kt")
public void testGetter() throws Exception {
runTest("idea/testData/highlighter/deprecated/Getter.kt");
}
@TestMetadata("Inc.kt")
public void testInc() throws Exception {
runTest("idea/testData/highlighter/deprecated/Inc.kt");
}
@TestMetadata("Invalid.kt")
public void testInvalid() throws Exception {
runTest("idea/testData/highlighter/deprecated/Invalid.kt");
}
@TestMetadata("Invoke.kt")
public void testInvoke() throws Exception {
runTest("idea/testData/highlighter/deprecated/Invoke.kt");
}
@TestMetadata("Operation.kt")
public void testOperation() throws Exception {
runTest("idea/testData/highlighter/deprecated/Operation.kt");
}
@TestMetadata("Property.kt")
public void testProperty() throws Exception {
runTest("idea/testData/highlighter/deprecated/Property.kt");
}
@TestMetadata("RangeTo.kt")
public void testRangeTo() throws Exception {
runTest("idea/testData/highlighter/deprecated/RangeTo.kt");
}
@TestMetadata("Setter.kt")
public void testSetter() throws Exception {
runTest("idea/testData/highlighter/deprecated/Setter.kt");
}
@TestMetadata("SuperCall.kt")
public void testSuperCall() throws Exception {
runTest("idea/testData/highlighter/deprecated/SuperCall.kt");
}
@TestMetadata("Trait.kt")
public void testTrait() throws Exception {
runTest("idea/testData/highlighter/deprecated/Trait.kt");
}
}
}

View File

@@ -5,11 +5,20 @@
package org.jetbrains.kotlin.idea.resolve
import com.intellij.testFramework.LightProjectDescriptor
import org.jetbrains.kotlin.idea.completion.test.configureWithExtraFile
import org.jetbrains.kotlin.idea.fir.FirResolution
import org.jetbrains.kotlin.idea.test.KotlinLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.KotlinWithJdkAndRuntimeLightProjectDescriptor
import org.jetbrains.kotlin.idea.test.ProjectDescriptorWithStdlibSources
import org.jetbrains.kotlin.test.InTextDirectivesUtils
abstract class AbstractFirReferenceResolveTest : AbstractReferenceResolveTest() {
override fun isFirPlugin(): Boolean = true
override fun getProjectDescriptor(): KotlinLightProjectDescriptor =
KotlinWithJdkAndRuntimeLightProjectDescriptor.INSTANCE_FULL_JDK
override fun setUp() {
super.setUp()
FirResolution.enabled = true

View File

@@ -0,0 +1,34 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compileOnly(project(":compiler:psi"))
compileOnly(project(":compiler:frontend"))
compileOnly(project(":core:type-system"))
compileOnly(project(":idea:idea-frontend-independent"))
compileOnly(project(":compiler:psi"))
compileOnly(intellijCoreDep())
compileOnly(intellijDep())
Platform[191].orLower {
compileOnly(intellijDep()) { includeJars("java-api", "java-impl") }
}
Platform[192].orHigher {
compileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
}
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
testsJar()
projectTest {
dependsOn(":dist")
workingDir = rootDir
}

View File

@@ -0,0 +1,54 @@
/*
* 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.idea.frontend.api
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtNamedFunction
sealed class CallInfo {
abstract val isSuspendCall: Boolean
abstract val targetFunction: PsiElement?
}
data class VariableAsFunctionCallInfo(val target: PsiElement, override val isSuspendCall: Boolean) : CallInfo() {
override val targetFunction: PsiElement? = null
}
data class VariableAsFunctionLikeCallInfo(val target: PsiElement, val invokeFunction: KtNamedFunction) : CallInfo() {
override val isSuspendCall: Boolean get() = invokeFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
override val targetFunction: PsiElement? get() = invokeFunction
}
// SimpleFunctionCallInfo
sealed class SimpleFunctionCallInfo : CallInfo() {
abstract override val targetFunction: PsiElement
}
data class SimpleKtFunctionCallInfo(override val targetFunction: KtNamedFunction) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean get() = targetFunction.hasModifier(KtTokens.SUSPEND_KEYWORD)
}
data class SimpleJavaFunctionCallInfo(override val targetFunction: PsiMethod) : SimpleFunctionCallInfo() {
override val isSuspendCall: Boolean = false
}
// ConstructorCallInfo
//TODO
object ConstructorCallInfo : CallInfo() {
// abstract val targetConstructor: PsiElement?
final override val isSuspendCall: Boolean = false
override val targetFunction: PsiElement? = null
}
//data class SimpleKtConstructorCallInfo(override val targetConstructor: KtConstructor<*>) : ConstructorCallInfo()
//data class SimpleJavaConstructorCallInfo(override val targetConstructor: PsiMethod) : ConstructorCallInfo()

View File

@@ -0,0 +1,31 @@
/*
* 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.idea.frontend.api
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
abstract class FrontendAnalysisSession {
abstract fun getSmartCastedToTypes(expression: KtExpression): Collection<KotlinTypeMarker>?
abstract fun getImplicitReceiverSmartCasts(expression: KtExpression): Collection<ImplicitReceiverSmartCast>
abstract fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KotlinTypeMarker?
abstract fun renderType(type: KotlinTypeMarker): String
abstract fun getKtExpressionType(expression: KtExpression): KotlinTypeMarker?
abstract fun isSubclassOf(klass: KtClassOrObject, superClassId: ClassId): Boolean
abstract fun getDiagnosticsForElement(element: KtElement): Collection<Diagnostic>
abstract fun resolveCall(call: KtCallExpression): CallInfo?
abstract fun resolveCall(call: KtBinaryExpression): CallInfo?
}

View File

@@ -0,0 +1,14 @@
/*
* 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.idea.frontend.api
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
data class ImplicitReceiverSmartCast(val types: Collection<KotlinTypeMarker>, val kind: ImplicitReceiverSmartcastKind)
enum class ImplicitReceiverSmartcastKind {
DISPATCH, EXTENSION
}

View File

@@ -0,0 +1,48 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
compile(project(":compiler:psi"))
compile(project(":idea:idea-frontend-independent"))
compile(project(":idea:idea-frontend-api"))
compile(project(":idea:idea-core"))
compile(project(":compiler:fir:fir2ir"))
compile(project(":compiler:fir:resolve"))
compile(project(":compiler:fir:checkers"))
compile(project(":compiler:fir:java"))
compile(project(":compiler:fir:jvm"))
compile(intellijDep())
compile(intellijCoreDep())
// <temp>
compile(project(":idea:idea-core"))
// </temp>
testCompile(toolsJar())
testCompile(projectTests(":idea"))
testCompile(projectTests(":compiler:tests-common"))
testCompile(projectTests(":idea:idea-test-framework"))
testCompile(project(":kotlin-test:kotlin-test-junit"))
testCompile(commonDep("junit:junit"))
Platform[192].orHigher {
compile(intellijPluginDep("java"))
}
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
if (rootProject.findProperty("idea.fir.plugin") == "true") {
projectTest {
dependsOn(":dist")
workingDir = rootDir
}
}
testsJar()

View File

@@ -0,0 +1,145 @@
/*
* 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.idea.fir
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.idea.stubindex.KotlinFullClassNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionFqnNameIndex
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelTypeAliasFqNameIndex
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedFunction
//todo introduce LibraryModificationTracker based cache?
object FirIdeDeserializedDeclarationSourceProvider {
fun findPsi(fir: FirElement, project: Project): PsiElement? {
return when (fir) {
is FirSimpleFunction -> provideSourceForFunction(fir, project)
is FirProperty -> provideSourceForProperty(fir, project)
is FirClass<*> -> provideSourceForClass(fir, project)
is FirTypeAlias -> provideSourceForTypeAlias(fir, project)
is FirConstructor -> provideSourceForConstructor(fir, project)
else -> null
}
}
private fun provideSourceForFunction(
function: FirSimpleFunction,
project: Project
): PsiElement? {
val candidates = if (function.isTopLevel) {
KotlinTopLevelFunctionFqnNameIndex.getInstance().get(
function.symbol.callableId.asFqNameForDebugInfo().asString(),
project,
function.scope(project)
).filter(KtNamedFunction::isCompiled)
} else {
function.containingKtClass(project)?.body?.functions
?.filter { it.name == function.name.asString() && it.isCompiled() }
.orEmpty()
}
return function.chooseCorrespondingPsi(candidates)
}
private fun provideSourceForProperty(property: FirProperty, project: Project): PsiElement? {
val candidates = if (property.isTopLevel) {
KotlinTopLevelFunctionFqnNameIndex.getInstance().get(
property.symbol.callableId.asFqNameForDebugInfo().asString(),
project,
property.scope(project)
)
} else {
property.containingKtClass(project)?.declarations
?.filter { it.name == property.name.asString() }
.orEmpty()
}
return candidates.firstOrNull(KtElement::isCompiled)
}
private fun provideSourceForClass(klass: FirClass<*>, project: Project): PsiElement? =
classByClassId(klass.symbol.classId, klass.scope(project), project)
private fun provideSourceForTypeAlias(alias: FirTypeAlias, project: Project): PsiElement? {
val candidates = KotlinTopLevelTypeAliasFqNameIndex.getInstance().get(
alias.symbol.classId.asStringForUsingInIndexes(),
project,
alias.scope(project)
)
return candidates.firstOrNull(KtElement::isCompiled)
}
private fun provideSourceForConstructor(
constructor: FirConstructor,
project: Project
): PsiElement? {
val containingKtClass = constructor.containingKtClass(project) ?: return null
if (constructor.isPrimary) return containingKtClass.primaryConstructor
return constructor.chooseCorrespondingPsi(containingKtClass.secondaryConstructors)
}
private fun FirFunction<*>.chooseCorrespondingPsi(
candidates: Collection<KtFunction>
): KtFunction? {
if (candidates.isEmpty()) return null
for (candidate in candidates) {
assert(candidate.isCompiled()) {
"Candidate should be decompiled from metadata because it should have fqName types as we don't use resolve here"
}
if (KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(candidate, this)) {
return candidate
}
}
return null
}
private fun FirDeclaration.scope(project: Project): GlobalSearchScope {
return GlobalSearchScope.allScope(project)
/* TODO:
val session = session as? FirLibrarySession
return session?.scope ?: GlobalSearchScope.allScope(project)*/
}
private fun FirCallableDeclaration<*>.containingKtClass(project: Project): KtClassOrObject? =
symbol.callableId.classId?.let { classByClassId(it, scope(project), project) }
private fun classByClassId(classId: ClassId, scope: GlobalSearchScope, project: Project): KtClassOrObject? {
val fqName = classId.asStringForUsingInIndexes().let { classIdMapping[it] ?: it }
return KotlinFullClassNameIndex.getInstance().get(
fqName,
project,
scope
).firstOrNull(KtElement::isCompiled)
}
private val FirCallableDeclaration<*>.isTopLevel
get() = symbol.callableId.className == null
private fun ClassId.asStringForUsingInIndexes() = asString().replace('/', '.')
private val classIdMapping = (0..23).associate { i ->
"kotlin.Function$i" to "kotlin.jvm.functions.Function$i"
}
}
private fun KtElement.isCompiled(): Boolean = containingKtFile.isCompiled
fun FirElement.findPsi(project: Project): PsiElement? =
psi ?: FirIdeDeserializedDeclarationSourceProvider.findPsi(this, project)
fun FirElement.findPsi(session: FirSession): PsiElement? =
findPsi(session.sessionProvider!!.project)

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.idea.fir
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.ModificationTracker
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.analyzer.TrackableModuleInfo
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
@@ -60,5 +59,5 @@ class FirIdeResolveStateServiceImpl(val project: Project) : FirIdeResolveStateSe
}
override val fallbackModificationTracker: ModificationTracker? =
KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker
org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService.getInstance(project).outOfBlockModificationTracker
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -18,6 +18,8 @@ import org.jetbrains.kotlin.fir.extensions.BunchOfRegisteredExtensions
import org.jetbrains.kotlin.fir.extensions.extensionService
import org.jetbrains.kotlin.fir.extensions.registerExtensions
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo
import org.jetbrains.kotlin.idea.caches.project.LibrarySourceInfo
import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.psi.KtElement
@@ -27,13 +29,18 @@ interface FirModuleResolveState {
val sessionProvider: FirProjectSessionProvider
fun getSession(psi: KtElement): FirSession {
val moduleInfo = psi.getModuleInfo() as ModuleSourceInfo
val moduleInfo = psi.getModuleInfo()
return getSession(psi.project, moduleInfo)
}
fun getSession(project: Project, moduleInfo: ModuleSourceInfo): FirSession {
fun getSession(project: Project, moduleInfo: IdeaModuleInfo): FirSession {
sessionProvider.getSession(moduleInfo)?.let { return it }
return synchronized(moduleInfo.module) {
val lock = when (moduleInfo) {
is ModuleSourceInfo -> moduleInfo.module
is LibrarySourceInfo -> moduleInfo.library
else -> TODO(moduleInfo.toString())
}
return synchronized(lock) {
val session = sessionProvider.getSession(moduleInfo) ?: FirIdeJavaModuleBasedSession(
project, moduleInfo, sessionProvider, moduleInfo.contentScope()
).also { moduleBasedSession ->
@@ -89,7 +96,7 @@ class FirModuleResolveStateImpl(override val sessionProvider: FirProjectSessionP
}
override fun record(psi: KtElement, fir: FirElement) {
cache[psi] = fir
cache.putIfAbsent(psi, fir)
}
override fun record(psi: KtElement, diagnostic: Diagnostic) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -1,10 +1,11 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
* 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.idea.fir
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.openapi.progress.ProgressIndicatorProvider
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirElement
@@ -33,7 +34,6 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.util.containingNonLocalDeclaration
private val FirResolvePhase.stubMode: Boolean
get() = this <= FirResolvePhase.DECLARATIONS
@@ -52,7 +52,8 @@ private fun FirFile.findCallableMember(
return provider.getClassDeclaredCallableSymbols(ClassId(packageFqName, klassFqName, false), declName)
.find { symbol: FirCallableSymbol<*> ->
symbol.fir.psi == callableMember
}?.fir ?: error("Cannot find FIR callable declaration ${CallableId(packageFqName, klassFqName, declName)}")
}?.fir
?: error("Cannot find FIR callable declaration ${CallableId(packageFqName, klassFqName, declName)}")
}
// NB: not sure it's correct to use member scope provider from here (because of possible changes)
val memberScope = FirPackageMemberScope(this.packageFqName, session)
@@ -224,12 +225,35 @@ private class FirDesignatedBodyResolveTransformerForIDE(
}
}
inline fun <reified E : FirElement> KtElement.getOrBuildFirSafe(
state: FirModuleResolveState,
phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE
) = getOrBuildFir(state, phase) as? E
private fun KtElement.getNonLocalContainingDeclarationWithFqName(): KtDeclaration? {
var container = parent
while (container != null && container !is KtFile) {
if (container is KtDeclaration
&& (container is KtClassOrObject || container is KtDeclarationWithBody)
&& !KtPsiUtil.isLocal(container)
&& container.name != null
&& container !is KtEnumEntry
&& container.containingClassOrObject !is KtEnumEntry
) {
return container
}
container = container.parent
}
return null
}
fun KtElement.getOrBuildFir(
state: FirModuleResolveState,
phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE
): FirElement {
val containerFir: FirDeclaration =
when (val container = this.containingNonLocalDeclaration()) {
when (val container = getNonLocalContainingDeclarationWithFqName()) {
is KtCallableDeclaration -> container.getOrBuildFir(state, phase)
is KtClassOrObject -> container.getOrBuildFir(state, phase)
null -> containingKtFile.getOrBuildFir(state, phase)

View File

@@ -0,0 +1,27 @@
/*
* 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.idea.fir
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.references.FirReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.util.OperatorNameConventions
fun FirFunctionCall.isImplicitFunctionCall(): Boolean {
if (dispatchReceiver !is FirQualifiedAccessExpression) return false
val resolvedCalleeSymbol = (calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
return (resolvedCalleeSymbol as? FirNamedFunctionSymbol)?.fir?.name == OperatorNameConventions.INVOKE
}
fun FirFunctionCall.getCalleeSymbol(): FirBasedSymbol<*>? =
calleeReference.getResolvedSymbolOfNameReference()
fun FirReference.getResolvedSymbolOfNameReference(): FirBasedSymbol<*>? =
(this as? FirResolvedNamedReference)?.resolvedSymbol

View File

@@ -0,0 +1,185 @@
/*
* 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.idea.fir
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.scopes.FirScope
import org.jetbrains.kotlin.fir.scopes.FirScopeProvider
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.types.Variance
// TODO replace with structural type comparision?
object KtDeclarationAndFirDeclarationEqualityChecker {
fun representsTheSameDeclaration(psi: KtFunction, fir: FirFunction<*>): Boolean {
if ((fir.receiverTypeRef != null) != (psi.receiverTypeReference != null)) return false
if (fir.receiverTypeRef != null
&& !isTheSameTypes(
psi.receiverTypeReference!!,
fir.receiverTypeRef!!,
fir.session,
isVararg = false
)
) {
return false
}
if (fir.valueParameters.size != psi.valueParameters.size) return false
fir.valueParameters.zip(psi.valueParameters) { expectedParameter, candidateParameter ->
if (expectedParameter.name.toString() != candidateParameter.name) return false
if (expectedParameter.isVararg != candidateParameter.isVarArg) return false
val candidateParameterType = candidateParameter.typeReference ?: return false
if (!isTheSameTypes(
candidateParameterType,
expectedParameter.returnTypeRef,
fir.session,
isVararg = expectedParameter.isVararg
)
) {
return false
}
}
return true
}
@OptIn(ExperimentalStdlibApi::class)
private fun FirTypeRef.renderTypeAsKotlinType(isVararg: Boolean = false): String {
val rendered = when (this) {
is FirResolvedTypeRef -> type.renderTypeAsKotlinType()
is FirUserTypeRef -> {
val renderedQualifier = qualifier.joinToString(separator = ".") { part ->
buildString {
append(part.name)
if (part.typeArguments.isNotEmpty()) {
part.typeArguments.joinTo(this, prefix = "<", postfix = ">") { it.renderTypeAsKotlinType() }
}
}
}
if (isMarkedNullable) "$renderedQualifier?" else renderedQualifier
}
is FirFunctionTypeRef -> {
val classId = if (isSuspend) {
KotlinBuiltIns.getSuspendFunctionClassId(parametersCount)
} else {
KotlinBuiltIns.getFunctionClassId(parametersCount)
}
buildString {
append(classId.asSingleFqName().toString())
val parameters = buildList {
receiverTypeRef?.let(::add)
valueParameters.mapTo(this) { it.returnTypeRef }
returnTypeRef.let(::add)
}
if (parameters.isNotEmpty()) {
append(parameters.joinToString(prefix = "<", postfix = ">") { it.renderTypeAsKotlinType() })
}
}
}
else -> error("Invalid type reference $this")
}
return if (isVararg) {
"kotlin.Array<out $rendered>"
} else {
rendered
}
}
private fun FirTypeProjection.renderTypeAsKotlinType() = when (this) {
is FirStarProjection -> "*"
is FirTypeProjectionWithVariance -> buildString {
append(variance.label)
if (variance != Variance.INVARIANT) {
append(" ")
}
append(typeRef.renderTypeAsKotlinType())
}
else -> error("Invalid type projection $this")
}
private fun isTheSameTypes(
psiTypeReference: KtTypeReference,
coneTypeReference: FirTypeRef,
session: FirSession,
isVararg: Boolean
): Boolean =
psiTypeReference.toKotlinTypReference(session).renderTypeAsKotlinType(isVararg) == coneTypeReference.renderTypeAsKotlinType()
private fun KtTypeReference.toKotlinTypReference(session: FirSession): FirTypeRef {
// Maybe resolve all types here to not to work with FirTypeRef directly
return RawFirBuilder(session, DummyScopeProvider, stubMode = true).buildTypeReference(this)
}
private fun ConeKotlinType.renderTypeAsKotlinType(): String {
val rendered = when (this) {
is ConeClassLikeType -> buildString {
append(lookupTag.classId.asString())
if (typeArguments.isNotEmpty()) {
append(typeArguments.joinToString(prefix = "<", postfix = ">", separator = ", ") { it.renderTypeAsKotlinType() })
}
}
is ConeTypeVariableType -> lookupTag.name.asString()
is ConeLookupTagBasedType -> lookupTag.name.asString()
is ConeFlexibleType -> {
// Can be present as return type
"${lowerBound.renderTypeAsKotlinType()}..${upperBound.renderTypeAsKotlinType()}"
}
else -> error("Type $this should not be present in Kotlin declaration")
}.replace('/', '.')
return rendered + nullability.suffix
}
private fun ConeTypeProjection.renderTypeAsKotlinType(): String = when (this) {
ConeStarProjection -> "*"
is ConeKotlinTypeProjectionIn -> "in ${type.renderTypeAsKotlinType()}"
is ConeKotlinTypeProjectionOut -> "out ${type.renderTypeAsKotlinType()}"
is ConeKotlinType -> renderTypeAsKotlinType()
}
@TestOnly
internal fun renderPsi(ktFunction: KtFunction, session: FirSession): String = buildString {
appendLine("receiver: ${ktFunction.receiverTypeReference?.toKotlinTypReference(session)?.renderTypeAsKotlinType()}")
ktFunction.valueParameters.forEach { parameter ->
appendLine("${parameter.name}: ${parameter.typeReference?.toKotlinTypReference(session)?.renderTypeAsKotlinType()}")
}
appendLine("return: ${ktFunction.typeReference?.toKotlinTypReference(session)?.renderTypeAsKotlinType()}")
}
@TestOnly
internal fun renderFir(firFunction: FirFunction<*>): String = buildString {
appendLine("receiver: ${firFunction.receiverTypeRef?.renderTypeAsKotlinType()}")
firFunction.valueParameters.forEach { parameter ->
appendLine("${parameter.name}: ${parameter.returnTypeRef.renderTypeAsKotlinType()}")
}
appendLine("return: ${firFunction.returnTypeRef.renderTypeAsKotlinType()}")
}
private object DummyScopeProvider : FirScopeProvider() {
override fun getUseSiteMemberScope(klass: FirClass<*>, useSiteSession: FirSession, scopeSession: ScopeSession): FirScope {
shouldNotBeCalled()
}
override fun getStaticMemberScopeForCallables(
klass: FirClass<*>,
useSiteSession: FirSession,
scopeSession: ScopeSession
): FirScope? {
shouldNotBeCalled()
}
override fun getNestedClassifierScope(klass: FirClass<*>, useSiteSession: FirSession, scopeSession: ScopeSession): FirScope? {
shouldNotBeCalled()
}
private fun shouldNotBeCalled(): Nothing =
error("Should not be called in RawFirBuilder while converting KtTypeReference")
}
}

View File

@@ -0,0 +1,154 @@
/*
* 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.idea.frontend.api.fir
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMethod
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.resolve.transformers.firClassLike
import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.idea.fir.*
import org.jetbrains.kotlin.idea.frontend.api.*
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper
import org.jetbrains.kotlin.idea.references.FirReferenceResolveHelper.toTargetPsi
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.types.model.KotlinTypeMarker
class AnalysisSessionFirImpl internal constructor(
private val state: FirModuleResolveState
) : FrontendAnalysisSession() {
override fun getSmartCastedToTypes(expression: KtExpression): Collection<KotlinTypeMarker>? {
// TODO filter out not used smartcasts
return (expression.toFir() as? FirExpressionWithSmartcast)?.typesFromSmartCast
}
@OptIn(ExperimentalStdlibApi::class)
override fun getImplicitReceiverSmartCasts(expression: KtExpression): Collection<ImplicitReceiverSmartCast> {
// TODO filter out not used smartcasts
val qualifiedExpression = expression.getOrBuildFir(state) as? FirQualifiedAccessExpression ?: return emptyList()
if (qualifiedExpression.dispatchReceiver !is FirExpressionWithSmartcast
&& qualifiedExpression.extensionReceiver !is FirExpressionWithSmartcast
) return emptyList()
return buildList {
(qualifiedExpression.dispatchReceiver as? FirExpressionWithSmartcast)?.let { smartCasted ->
ImplicitReceiverSmartCast(smartCasted.typesFromSmartCast, ImplicitReceiverSmartcastKind.DISPATCH)
}?.let(::add)
(qualifiedExpression.extensionReceiver as? FirExpressionWithSmartcast)?.let { smartCasted ->
ImplicitReceiverSmartCast(smartCasted.typesFromSmartCast, ImplicitReceiverSmartcastKind.EXTENSION)
}?.let(::add)
}
}
override fun renderType(type: KotlinTypeMarker): String =
type.asConeType().render()
override fun getReturnTypeForKtDeclaration(declaration: KtDeclaration): KotlinTypeMarker? =
declaration.toFir<FirCallableDeclaration<*>>()?.returnTypeRef?.coneTypeSafe()
override fun getKtExpressionType(expression: KtExpression): ConeKotlinType? =
expression.toFir<FirExpression>()?.typeRef?.coneTypeSafe()
override fun isSubclassOf(klass: KtClassOrObject, superClassId: ClassId): Boolean {
var result = false
forEachSubClass(klass.toFir() ?: return false) { type ->
result = result || type.firClassLike(state.getSession(klass))?.symbol?.classId == superClassId
}
return result
}
override fun getDiagnosticsForElement(element: KtElement): Collection<Diagnostic> {
element.containingKtFile.getOrBuildFirWithDiagnostics(state)
return state.getDiagnostics(element)
}
override fun resolveCall(call: KtBinaryExpression): CallInfo? {
val firCall = call.toFir<FirFunctionCall>() ?: return null
return resolveCall(firCall, call)
}
override fun resolveCall(call: KtCallExpression): CallInfo? {
val firCall = call.toFir<FirFunctionCall>() ?: return null
return resolveCall(firCall, call)
}
private fun resolveCall(firCall: FirFunctionCall, callExpression: KtExpression): CallInfo? {
val session = callExpression.getSession()
val resolvedFunctionPsi = firCall.calleeReference.toTargetPsi(session)
val resolvedCalleeSymbol = (firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol
return when {
resolvedCalleeSymbol is FirConstructorSymbol -> {
ConstructorCallInfo//todo use proper constructor info
}
firCall.dispatchReceiver is FirQualifiedAccessExpression && firCall.isImplicitFunctionCall() -> {
val target = with(FirReferenceResolveHelper) {
val calleeReference = (firCall.dispatchReceiver as FirQualifiedAccessExpression).calleeReference
calleeReference.toTargetPsi(session)
}
when (target) {
null -> null
is KtValVarKeywordOwner, is PsiField -> {
val functionSymbol =
(firCall.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirNamedFunctionSymbol
when (functionSymbol?.callableId) {
null -> null
in kotlinFunctionInvokeCallableIds -> VariableAsFunctionCallInfo(target, functionSymbol.fir.isSuspend)
else -> (resolvedFunctionPsi as? KtNamedFunction)?.let { VariableAsFunctionLikeCallInfo(target, it) }
}
}
else -> resolvedFunctionPsi?.asSimpleFunctionCall()
}
}
else -> resolvedFunctionPsi?.asSimpleFunctionCall()
}
}
private fun PsiElement.asSimpleFunctionCall() = when (this) {
is KtNamedFunction -> SimpleKtFunctionCallInfo(this)
is PsiMethod -> SimpleJavaFunctionCallInfo(this)
else -> null
}
private fun KtElement.getSession() = state.getSession(this)
private inline fun <reified F : FirElement> KtElement.toFir(phase: FirResolvePhase = FirResolvePhase.BODY_RESOLVE): F? =
getOrBuildFir(state, phase) as? F
private fun forEachSubClass(firClass: FirClass<*>, action: (FirResolvedTypeRef) -> Unit) {
firClass.superTypeRefs.forEach { superType ->
(superType as? FirResolvedTypeRef)?.let(action)
(superType.firClassLike(firClass.session) as? FirClass<*>?)?.let { forEachSubClass(it, action) }
}
}
companion object {
fun forElement(element: KtElement): FrontendAnalysisSession =
AnalysisSessionFirImpl(element.firResolveState())
private fun KotlinTypeMarker.asConeType(): ConeKotlinType =
this as? ConeKotlinType ?: error("$this should be ConeKotlinType")
private val kotlinFunctionInvokeCallableIds = (0..23).flatMapTo(hashSetOf()) { arity ->
listOf(
CallableId(KotlinBuiltIns.getFunctionClassId(arity), Name.identifier("invoke")),
CallableId(KotlinBuiltIns.getSuspendFunctionClassId(arity), Name.identifier("invoke"))
)
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.idea.highlighter
import com.intellij.lang.jvm.JvmModifier
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.psi.*
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isAbstract
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal fun textAttributesKeyForPropertyDeclaration(declaration: PsiElement): TextAttributesKey? = when (declaration) {
is KtProperty -> textAttributesForKtPropertyDeclaration(declaration)
is KtParameter -> textAttributesForKtParameterDeclaration(declaration)
is PsiLocalVariable -> Colors.LOCAL_VARIABLE
is PsiParameter -> Colors.PARAMETER
is PsiField -> Colors.INSTANCE_PROPERTY
else -> null
}
internal fun textAttributesForKtParameterDeclaration(parameter: KtParameter) =
if (parameter.valOrVarKeyword != null) Colors.INSTANCE_PROPERTY
else Colors.PARAMETER
internal fun textAttributesForKtPropertyDeclaration(property: KtProperty): TextAttributesKey? = when {
property.isExtensionDeclaration() -> Colors.EXTENSION_PROPERTY
property.isLocal -> Colors.LOCAL_VARIABLE
property.isTopLevel -> {
if (property.isCustomPropertyDeclaration()) Colors.PACKAGE_PROPERTY_CUSTOM_PROPERTY_DECLARATION
else Colors.PACKAGE_PROPERTY
}
else -> {
if (property.isCustomPropertyDeclaration()) Colors.INSTANCE_PROPERTY_CUSTOM_PROPERTY_DECLARATION
else Colors.INSTANCE_PROPERTY
}
}
private fun KtProperty.isCustomPropertyDeclaration() =
getter?.bodyExpression != null || setter?.bodyExpression != null
@Suppress("UnstableApiUsage")
internal fun textAttributesKeyForTypeDeclaration(declaration: PsiElement): TextAttributesKey? = when {
declaration is KtTypeParameter || declaration is PsiTypeParameter -> Colors.TYPE_PARAMETER
declaration is KtTypeAlias -> Colors.TYPE_ALIAS
declaration is KtClass -> textAttributesForClass(declaration)
declaration is PsiClass && declaration.isInterface && !declaration.isAnnotationType -> Colors.TRAIT
declaration.isAnnotationClass() -> Colors.ANNOTATION
declaration is KtObjectDeclaration -> Colors.OBJECT
declaration is PsiEnumConstant -> Colors.ENUM_ENTRY
declaration is PsiClass && declaration.hasModifier(JvmModifier.ABSTRACT) -> Colors.ABSTRACT_CLASS
declaration is PsiClass -> Colors.CLASS
else -> null
}
fun textAttributesForClass(klass: KtClass): TextAttributesKey = when {
klass.isInterface() -> Colors.TRAIT
klass.isAnnotation() -> Colors.ANNOTATION
klass is KtEnumEntry -> Colors.ENUM_ENTRY
klass.isAbstract() -> Colors.ABSTRACT_CLASS
else -> Colors.CLASS
}
internal fun PsiElement.isAnnotationClass() =
this is KtClass && isAnnotation() || this is PsiClass && isAnnotationType

View File

@@ -0,0 +1,73 @@
/*
* 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.idea.highlighter
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
import org.jetbrains.kotlin.idea.highlighter.visitors.FirAfterResolveHighlightingVisitor
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
class KotlinFirPsiChecker : AbstractKotlinPsiChecker() {
override fun shouldHighlight(file: KtFile): Boolean {
return true // todo
}
override fun annotateElement(element: PsiElement, containingFile: KtFile, holder: AnnotationHolder) {
if (element !is KtElement) return
val analysisSession = AnalysisSessionFirImpl.forElement(element)
highlightDiagnostics(element, analysisSession, holder)
FirAfterResolveHighlightingVisitor
.createListOfVisitors(analysisSession, holder)
.forEach(element::accept)
}
private fun highlightDiagnostics(element: KtElement, analysisSession: FrontendAnalysisSession, holder: AnnotationHolder) {
val diagnostics = analysisSession.getDiagnosticsForElement(element)
if (diagnostics.isEmpty()) return
if (diagnostics.none(Diagnostic::isValid)) return
if (shouldHighlightErrors(element)) {
highlightDiagnostics(diagnostics, holder)
}
}
private fun highlightDiagnostics(diagnostics: Collection<Diagnostic>, holder: AnnotationHolder) {
diagnostics.groupBy { it.factory }.forEach { group -> registerDiagnosticAnnotations(group.value, holder) }
}
private fun registerDiagnosticAnnotations(diagnostics: List<Diagnostic>, holder: AnnotationHolder) {
assert(diagnostics.isNotEmpty())
val diagnostic = diagnostics.first()
val ranges = diagnostic.textRanges
ranges.forEach { range ->
diagnostics.forEach { diagnostic ->
Diagnostic2Annotation.createAnnotation(
diagnostic,
range,
holder,
nonDefaultMessage = null,
textAttributes = null,
highlightType = null,
renderMessage = IdeErrorMessages::render
)
}
}
}
private fun shouldHighlightErrors(element: KtElement): Boolean {
return true // todo
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.idea.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.util.elementType
import org.jetbrains.kotlin.idea.highlighter.*
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class DeclarationHighlightingVisitor(holder: AnnotationHolder) : HighlightingVisitor(holder) {
override fun visitTypeAlias(typeAlias: KtTypeAlias) {
highlightNamedDeclaration(typeAlias, Colors.TYPE_ALIAS)
super.visitTypeAlias(typeAlias)
}
override fun visitObjectDeclaration(declaration: KtObjectDeclaration) {
highlightNamedDeclaration(declaration, Colors.OBJECT)
super.visitObjectDeclaration(declaration)
}
override fun visitClass(klass: KtClass) {
highlightNamedDeclaration(klass, textAttributesForClass(klass))
super.visitClass(klass)
}
override fun visitProperty(property: KtProperty) {
textAttributesForKtPropertyDeclaration(property)?.let { attributes ->
highlightNamedDeclaration(property, attributes)
}
highlightMutability(property)
super.visitProperty(property)
}
override fun visitParameter(parameter: KtParameter) {
textAttributesForKtParameterDeclaration(parameter)?.let { attributes ->
highlightNamedDeclaration(parameter, attributes)
}
highlightMutability(parameter)
super.visitParameter(parameter)
}
private fun <D> highlightMutability(declaration: D) where D : KtValVarKeywordOwner, D : KtNamedDeclaration {
if (declaration.valOrVarKeyword?.elementType == KtTokens.VAR_KEYWORD) {
highlightNamedDeclaration(declaration, Colors.MUTABLE_VARIABLE)
}
}
}
class DeclarationHighlightingExtension : BeforeResolveHighlightingExtension {
override fun createVisitor(holder: AnnotationHolder): HighlightingVisitor =
DeclarationHighlightingVisitor(holder)
}

View File

@@ -0,0 +1,65 @@
/*
* 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.idea.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.ImplicitReceiverSmartcastKind
import org.jetbrains.kotlin.psi.*
internal class ExpressionsSmartcastHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitExpression(expression: KtExpression) {
analysisSession.getImplicitReceiverSmartCasts(expression).forEach { (types, kind) ->
val receiverName = when (kind) {
ImplicitReceiverSmartcastKind.EXTENSION -> KotlinIdeaAnalysisBundle.message("extension.implicit.receiver")
ImplicitReceiverSmartcastKind.DISPATCH -> KotlinIdeaAnalysisBundle.message("implicit.receiver")
}
types.forEach { type ->
createInfoAnnotation(
expression,
KotlinIdeaAnalysisBundle.message(
"0.smart.cast.to.1",
receiverName,
analysisSession.renderType(type)
)
).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_RECEIVER
}
}
analysisSession.getSmartCastedToTypes(expression)?.forEach { type ->
createInfoAnnotation(
getSmartCastTarget(expression),
KotlinIdeaAnalysisBundle.message(
"smart.cast.to.0",
analysisSession.renderType(type)
)
).textAttributes = org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors.SMART_CAST_VALUE
}
//todo smartcast to null
super.visitExpression(expression)
}
}
private fun getSmartCastTarget(expression: KtExpression): PsiElement {
var target: PsiElement = expression
if (target is KtParenthesizedExpression) {
target = KtPsiUtil.deparenthesize(target) ?: expression
}
return when (target) {
is KtIfExpression -> target.ifKeyword
is KtWhenExpression -> target.whenKeyword
is KtBinaryExpression -> target.operationReference
else -> target
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.idea.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.HighlightingVisitor
abstract class FirAfterResolveHighlightingVisitor(
protected val analysisSession: FrontendAnalysisSession,
protected val holder: AnnotationHolder
) : HighlightingVisitor(holder) {
companion object {
fun createListOfVisitors(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
): List<FirAfterResolveHighlightingVisitor> = listOf(
TypeHighlightingVisitor(analysisSession, holder),
FunctionCallHighlightingVisitor(analysisSession, holder),
ExpressionsSmartcastHighlightingVisitor(analysisSession, holder),
VariableReferenceHighlightingVisitor(analysisSession, holder),
)
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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.idea.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.editor.colors.TextAttributesKey
import org.jetbrains.kotlin.idea.frontend.api.*
import org.jetbrains.kotlin.idea.refactoring.fqName.getKotlinFqName
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameOrNull
import org.jetbrains.kotlin.serialization.deserialization.KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class FunctionCallHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitBinaryExpression(expression: KtBinaryExpression) {
(expression.operationReference as? KtReferenceExpression)
?.takeIf {
// do not highlight assignment statement
(it as? KtOperationReferenceExpression)?.operationSignTokenType != KtTokens.EQ
}?.let { callee ->
analysisSession.resolveCall(expression)
?.takeIf { callInfo ->
// ignore arithmetic-like operator calls
(callInfo.targetFunction as? KtNamedFunction)?.hasModifier(KtTokens.OPERATOR_KEYWORD) != true
}
?.let { callInfo ->
getTextAttributesForCal(callInfo)?.let { attributes ->
highlightName(callee, attributes)
}
}
}
super.visitBinaryExpression(expression)
}
override fun visitCallExpression(expression: KtCallExpression) {
expression.calleeExpression
?.takeUnless { it is KtLambdaExpression }
?.takeUnless { it is KtCallExpression /* KT-16159 */}
?.let { callee ->
analysisSession.resolveCall(expression)?.let { callInfo ->
getTextAttributesForCal(callInfo)?.let { attributes ->
highlightName(callee, attributes)
}
}
}
super.visitCallExpression(expression)
}
private fun getTextAttributesForCal(callInfo: CallInfo): TextAttributesKey? = when {
callInfo.isSuspendCall -> Colors.SUSPEND_FUNCTION_CALL
callInfo is ConstructorCallInfo ->
Colors.CONSTRUCTOR_CALL
callInfo is SimpleKtFunctionCallInfo -> when {
callInfo.targetFunction.getKotlinFqName() == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME ->Colors.KEYWORD
callInfo.targetFunction.isExtensionDeclaration() -> Colors.EXTENSION_FUNCTION_CALL
callInfo.targetFunction.parent is KtFile -> Colors.PACKAGE_FUNCTION_CALL
else -> Colors.FUNCTION_CALL
}
callInfo is SimpleJavaFunctionCallInfo -> Colors.FUNCTION_CALL
callInfo is VariableAsFunctionCallInfo -> Colors.VARIABLE_AS_FUNCTION_CALL
callInfo is VariableAsFunctionLikeCallInfo -> Colors.VARIABLE_AS_FUNCTION_LIKE_CALL
else -> null
}
}

View File

@@ -0,0 +1,67 @@
/*
* 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.idea.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.NameHighlighter
import org.jetbrains.kotlin.idea.highlighter.isAnnotationClass
import org.jetbrains.kotlin.idea.highlighter.textAttributesKeyForTypeDeclaration
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class TypeHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
if (!NameHighlighter.namesHighlightingEnabled) return
if (expression.isCalleeExpression()) return
val parent = expression.parent
if (parent is KtInstanceExpressionWithLabel) {
// Do nothing: 'super' and 'this' are highlighted as a keyword
return
}
val target = expression.mainReference.resolve() ?: return
textAttributesKeyForTypeDeclaration(target)?.let { key ->
if (expression.isConstructorCallReference() && key != Colors.ANNOTATION) {
// Do not highlight constructor call as class reference
return@let
}
highlightName(computeHighlightingRangeForUsage(expression, target), key)
}
}
private fun computeHighlightingRangeForUsage(expression: KtSimpleNameExpression, target: PsiElement): TextRange {
val expressionRange = expression.textRange
if (!target.isAnnotationClass()) return expressionRange
// include '@' symbol if the reference is the first segment of KtAnnotationEntry
// if "Deprecated" is highlighted then '@' should be highlighted too in "@Deprecated"
val annotationEntry = PsiTreeUtil.getParentOfType(
expression, KtAnnotationEntry::class.java, /* strict = */false, KtValueArgumentList::class.java
)
val atSymbol = annotationEntry?.atSymbol ?: return expressionRange
return TextRange(atSymbol.textRange.startOffset, expression.textRange.endOffset)
}
}
private fun KtSimpleNameExpression.isCalleeExpression() =
(parent as? KtCallExpression)?.calleeExpression == this
private fun KtSimpleNameExpression.isConstructorCallReference(): Boolean {
val type = parent as? KtUserType ?: return false
val typeReference = type.parent as? KtTypeReference ?: return false
val constructorCallee = typeReference.parent as? KtConstructorCalleeExpression ?: return false
return constructorCallee.constructorReferenceExpression == this
}

View File

@@ -0,0 +1,79 @@
/*
* 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.idea.highlighter.visitors
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import com.intellij.psi.PsiVariable
import com.intellij.psi.util.elementType
import com.intellij.psi.util.parentOfType
import org.jetbrains.kotlin.idea.KotlinIdeaAnalysisBundle
import org.jetbrains.kotlin.idea.frontend.api.FrontendAnalysisSession
import org.jetbrains.kotlin.idea.highlighter.NameHighlighter
import org.jetbrains.kotlin.idea.highlighter.textAttributesKeyForPropertyDeclaration
import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingColors as Colors
internal class VariableReferenceHighlightingVisitor(
analysisSession: FrontendAnalysisSession,
holder: AnnotationHolder
) : FirAfterResolveHighlightingVisitor(analysisSession, holder) {
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
if (!NameHighlighter.namesHighlightingEnabled) return
if (expression.isAssignmentReference()) return
if (expression.parent is KtInstanceExpressionWithLabel) return
if (expression.isAutoCreatedItParameter()) {
createInfoAnnotation(
expression,
Colors.FUNCTION_LITERAL_DEFAULT_PARAMETER,
KotlinIdeaAnalysisBundle.message("automatically.declared.based.on.the.expected.type")
)
return
}
val target = expression.mainReference.resolve()
when {
target != null && expression.isBackingField(target) -> Colors.BACKING_FIELD_VARIABLE
target is PsiMethod -> Colors.SYNTHETIC_EXTENSION_PROPERTY
target != null -> textAttributesKeyForPropertyDeclaration(target)
else -> null
}?.let { attribute ->
highlightName(expression, attribute)
if (target?.isMutableVariable() == true) {
highlightName(expression, Colors.MUTABLE_VARIABLE)
}
}
}
private fun KtSimpleNameExpression.isAutoCreatedItParameter(): Boolean {
return getReferencedName() == "it" // todo
}
}
private fun PsiElement.isMutableVariable() = when {
this is KtValVarKeywordOwner && valOrVarKeyword?.elementType == KtTokens.VAR_KEYWORD -> true
this is PsiVariable && !hasModifierProperty(PsiModifier.FINAL) -> true
else -> false
}
private fun KtSimpleNameExpression.isAssignmentReference(): Boolean {
if (this !is KtOperationReferenceExpression) return false
return operationSignTokenType == KtTokens.EQ
}
private fun KtSimpleNameExpression.isBackingField(target: PsiElement): Boolean {
if (getReferencedName() != "field") return false
if (target !is KtProperty) return false
val accessor = parentOfType<KtPropertyAccessor>() ?: return false
return accessor.parent == target
}

View File

@@ -0,0 +1,21 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.idea.fir.FirModuleResolveState
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
interface FirKtReference : KtReference {
fun getResolvedToPsi(
analysisSession: AnalysisSessionFirImpl,
session: FirSession,
state: FirModuleResolveState
): Collection<PsiElement>
override val resolver get() = KtFirReferenceResolver
}

View File

@@ -0,0 +1,196 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.resolve.calls.SyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.firSymbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
import org.jetbrains.kotlin.fir.types.ConeLookupTagBasedType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.idea.fir.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
object FirReferenceResolveHelper {
fun FirResolvedTypeRef.toTargetPsi(session: FirSession): PsiElement? {
val type = type as? ConeLookupTagBasedType ?: return null
return (type.lookupTag.toSymbol(session) as? AbstractFirBasedSymbol<*>)?.fir?.findPsi(session)
}
fun ClassId.toTargetPsi(session: FirSession, calleeReference: FirReference? = null): PsiElement? {
val classLikeDeclaration = ConeClassLikeLookupTagImpl(this).toSymbol(session)?.fir
if (classLikeDeclaration is FirRegularClass) {
if (calleeReference is FirResolvedNamedReference) {
val callee = calleeReference.resolvedSymbol.fir as? FirCallableMemberDeclaration
// TODO: check callee owner directly?
if (callee !is FirConstructor && callee?.isStatic != true) {
classLikeDeclaration.companionObject?.let { return it.findPsi(session) }
}
}
}
return classLikeDeclaration?.findPsi(session)
}
fun FirReference.toTargetPsi(session: FirSession): PsiElement? {
return when (this) {
is FirResolvedNamedReference -> {
val targetFir = when (val symbol = resolvedSymbol) {
is SyntheticPropertySymbol -> {
val syntheticProperty = symbol.fir as FirSyntheticProperty
if (syntheticProperty.getter.delegate.symbol.callableId == symbol.accessorId) {
syntheticProperty.getter.delegate
} else {
syntheticProperty.setter!!.delegate
}
}
else -> symbol.fir
}
targetFir.findPsi(session)
}
is FirResolvedCallableReference -> {
resolvedSymbol.fir.findPsi(session)
}
is FirThisReference -> {
boundSymbol?.fir?.findPsi(session)
}
is FirSuperReference -> {
(superTypeRef as? FirResolvedTypeRef)?.toTargetPsi(session)
}
else -> {
null
}
}
}
internal fun resolveSimpleNameReference(
ref: KtSimpleNameReferenceFirImpl,
session: FirSession,
state: FirModuleResolveState
): Collection<PsiElement> {
val expression = ref.expression
when (val fir = expression.getOrBuildFir(state)) {
is FirResolvable -> {
val calleeReference =
if (fir is FirFunctionCall
&& fir.isImplicitFunctionCall()
&& expression is KtNameReferenceExpression
) {
// we are resolving implicit invoke call, like
// fun foo(a: () -> Unit) {
// <expression>a</expression>()
// }
(fir.dispatchReceiver as FirQualifiedAccessExpression).calleeReference
} else fir.calleeReference
return listOfNotNull(calleeReference.toTargetPsi(session))
}
is FirResolvedTypeRef -> {
return listOfNotNull(fir.toTargetPsi(session))
}
is FirResolvedQualifier -> {
val classId = fir.classId ?: return emptyList()
// Distinguish A.foo() from A(.Companion).foo()
// Make expression.parent as? KtDotQualifiedExpression local function
var parent = expression.parent as? KtDotQualifiedExpression
while (parent != null) {
val selectorExpression = parent.selectorExpression ?: break
if (selectorExpression === expression) {
parent = parent.parent as? KtDotQualifiedExpression
continue
}
val parentFir = selectorExpression.getOrBuildFir(state)
if (parentFir is FirQualifiedAccess) {
return listOfNotNull(classId.toTargetPsi(session, parentFir.calleeReference))
}
parent = parent.parent as? KtDotQualifiedExpression
}
return listOfNotNull(classId.toTargetPsi(session))
}
is FirAnnotationCall -> {
val type = fir.typeRef as? FirResolvedTypeRef ?: return emptyList()
return listOfNotNull(type.toTargetPsi(session))
}
is FirResolvedImport -> {
var parent = expression.parent
while (parent is KtDotQualifiedExpression) {
if (parent.selectorExpression !== expression) {
// Special: package reference in the middle of import directive
// import a.<caret>b.c.SomeClass
// TODO: return reference to PsiPackage
return listOf(expression)
}
parent = parent.parent
}
val classId = fir.resolvedClassId
if (classId != null) {
return listOfNotNull(classId.toTargetPsi(session))
}
val name = fir.importedName ?: return emptyList()
val symbolProvider = session.firSymbolProvider
return symbolProvider.getTopLevelCallableSymbols(fir.packageFqName, name)
.mapNotNull { it.fir.findPsi(session) } +
listOfNotNull(
symbolProvider
.getClassLikeSymbolByFqName(ClassId(fir.packageFqName, name))
?.fir?.findPsi(session)
)
}
is FirFile -> {
if (expression.getNonStrictParentOfType<KtPackageDirective>() != null) {
// Special: package reference in the middle of package directive
return listOf(expression)
}
return listOfNotNull(fir.findPsi(session))
}
is FirArrayOfCall -> {
// We can't yet find PsiElement for arrayOf, intArrayOf, etc.
return emptyList()
}
is FirReturnExpression -> {
return if (expression is KtLabelReferenceExpression) {
listOfNotNull(fir.target.labeledElement.findPsi(session))
} else emptyList()
}
is FirErrorNamedReference -> {
return emptyList()
}
else -> {
// Handle situation when we're in the middle/beginning of qualifier
// <caret>A.B.C.foo() or A.<caret>B.C.foo()
// NB: in this case we get some parent FIR, like FirBlock, FirProperty, FirFunction or the like
var parent = expression.parent as? KtDotQualifiedExpression
var unresolvedCounter = 1
while (parent != null) {
val selectorExpression = parent.selectorExpression ?: break
if (selectorExpression === expression) {
parent = parent.parent as? KtDotQualifiedExpression
continue
}
val parentFir = selectorExpression.getOrBuildFir(state)
if (parentFir is FirResolvedQualifier) {
var classId = parentFir.classId
while (unresolvedCounter > 0) {
unresolvedCounter--
classId = classId?.outerClassId
}
return listOfNotNull(classId?.toTargetPsi(session))
}
parent = parent.parent as? KtDotQualifiedExpression
unresolvedCounter++
}
return emptyList()
}
}
}
}

View File

@@ -0,0 +1,50 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.idea.fir.FirModuleResolveState
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtImportAlias
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
internal class KtSimpleNameReferenceFirImpl(
expression: KtSimpleNameExpression
) : KtSimpleNameReference(expression), FirKtReference {
override fun getResolvedToPsi(
analysisSession: AnalysisSessionFirImpl,
session: FirSession,
state: FirModuleResolveState
) = FirReferenceResolveHelper.resolveSimpleNameReference(this, session, state)
override fun doCanBeReferenceTo(candidateTarget: PsiElement): Boolean {
return true // TODO
}
override fun isReferenceToWithoutExtensionChecking(candidateTarget: PsiElement): Boolean {
return resolve() == candidateTarget //todo
}
override fun handleElementRename(newElementName: String): PsiElement? {
TODO("Not yet implemented")
}
override fun bindToElement(element: PsiElement, shorteningMode: ShorteningMode): PsiElement {
TODO("Not yet implemented")
}
override fun bindToFqName(fqName: FqName, shorteningMode: ShorteningMode, targetElement: PsiElement?): PsiElement {
TODO("Not yet implemented")
}
override fun getImportAlias(): KtImportAlias? {
TODO("Not yet implemented")
}
override val resolver get() = KtFirReferenceResolver
}

View File

@@ -0,0 +1,18 @@
/*
* 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.idea.references
class KotlinFirReferenceContributor : KotlinReferenceProviderContributor {
override fun registerReferenceProviders(registrar: KotlinPsiReferenceRegistrar) {
with(registrar) {
registerProvider(factory = ::KtSimpleNameReferenceFirImpl)
registerProvider(factory = ::KtForLoopInReferenceFirImpl)
registerProvider(factory = ::KtInvokeFunctionReferenceFirImpl)
registerProvider(factory = ::KtPropertyDelegationMethodsReferenceFirImpl)
registerProvider(factory = ::KtDestructuringDeclarationReferenceFirImpl)
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.FirComponentCall
import org.jetbrains.kotlin.idea.fir.*
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
import org.jetbrains.kotlin.psi.KtDestructuringDeclarationEntry
class KtDestructuringDeclarationReferenceFirImpl(
element: KtDestructuringDeclarationEntry
) : KtDestructuringDeclarationReference(element), FirKtReference {
override fun canRename(): Boolean = false //todo
override fun getResolvedToPsi(
analysisSession: AnalysisSessionFirImpl,
session: FirSession,
state: FirModuleResolveState
): Collection<PsiElement> {
val fir = expression.getOrBuildFirSafe<FirProperty>(state) ?: return emptyList()
val componentFunctionSymbol = (fir.initializer as? FirComponentCall)?.getCalleeSymbol() ?: return emptyList()
return listOfNotNull(componentFunctionSymbol.fir.findPsi(session))
}
}

View File

@@ -0,0 +1,28 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiElementResolveResult
import com.intellij.psi.ResolveResult
import com.intellij.psi.impl.source.resolve.ResolveCache
import org.jetbrains.kotlin.idea.fir.firResolveState
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
object KtFirReferenceResolver : ResolveCache.PolyVariantResolver<KtReference> {
class KotlinResolveResult(element: PsiElement) : PsiElementResolveResult(element)
override fun resolve(ref: KtReference, incompleteCode: Boolean): Array<ResolveResult> {
check(ref is FirKtReference) { "reference should be FirKtReference, but was ${ref::class}" }
check(ref is AbstractKtReference<*>) { "reference should be AbstractKtReference, but was ${ref::class}" }
val expression = ref.expression
val state = expression.firResolveState()
val session = state.getSession(expression)
val analysisSession = AnalysisSessionFirImpl(state)
val resolveToPsiElements = ref.getResolvedToPsi(analysisSession, session, state)
return resolveToPsiElements.map { KotlinResolveResult(it) }.toTypedArray()
}
}

View File

@@ -0,0 +1,44 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
import org.jetbrains.kotlin.fir.expressions.FirWhileLoop
import org.jetbrains.kotlin.idea.fir.FirModuleResolveState
import org.jetbrains.kotlin.idea.fir.findPsi
import org.jetbrains.kotlin.idea.fir.getOrBuildFirSafe
import org.jetbrains.kotlin.idea.fir.getResolvedSymbolOfNameReference
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
import org.jetbrains.kotlin.psi.KtForExpression
open class KtForLoopInReferenceFirImpl(expression: KtForExpression) : KtForLoopInReference(expression), FirKtReference {
override fun getResolvedToPsi(
analysisSession: AnalysisSessionFirImpl,
session: FirSession,
state: FirModuleResolveState
): Collection<PsiElement> {
val firLoop = expression.getOrBuildFirSafe<FirWhileLoop>(state) ?: return emptyList()
val condition = firLoop.condition as? FirFunctionCall
val iterator = run {
val callee = (condition?.explicitReceiver as? FirQualifiedAccessExpression)?.calleeReference
(callee?.getResolvedSymbolOfNameReference()?.fir as? FirProperty)?.getInitializerFunctionCall()
}
val hasNext = condition?.calleeReference?.getResolvedSymbolOfNameReference()
val next = (firLoop.block.statements.firstOrNull() as? FirProperty?)?.getInitializerFunctionCall()
return listOfNotNull(
iterator?.fir?.findPsi(session),
hasNext?.fir?.findPsi(session),
next?.fir?.findPsi(session),
)
}
private fun FirProperty.getInitializerFunctionCall() =
(initializer as? FirFunctionCall)?.calleeReference?.getResolvedSymbolOfNameReference()
}

View File

@@ -0,0 +1,32 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.idea.fir.FirModuleResolveState
import org.jetbrains.kotlin.idea.frontend.api.VariableAsFunctionLikeCallInfo
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtExpression
class KtInvokeFunctionReferenceFirImpl(expression: KtCallExpression) : KtInvokeFunctionReference(expression), FirKtReference {
override fun doRenameImplicitConventionalCall(newName: String?): KtExpression {
TODO("Not yet implemented")
}
override fun getResolvedToPsi(
analysisSession: AnalysisSessionFirImpl,
session: FirSession,
state: FirModuleResolveState
): Collection<PsiElement> {
val call = analysisSession.resolveCall(expression) ?: return emptyList()
if (call is VariableAsFunctionLikeCallInfo) {
return listOf(call.invokeFunction)
}
return emptyList()
}
}

View File

@@ -0,0 +1,40 @@
/*
* 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.idea.references
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
import org.jetbrains.kotlin.fir.expressions.FirStatement
import org.jetbrains.kotlin.idea.fir.*
import org.jetbrains.kotlin.idea.frontend.api.fir.AnalysisSessionFirImpl
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtPropertyDelegate
class KtPropertyDelegationMethodsReferenceFirImpl(
element: KtPropertyDelegate
) : KtPropertyDelegationMethodsReference(element), FirKtReference {
override fun getResolvedToPsi(
analysisSession: AnalysisSessionFirImpl,
session: FirSession,
state: FirModuleResolveState
): Collection<PsiElement> {
val property = (expression.parent as? KtElement)?.getOrBuildFirSafe<FirProperty>(state) ?: return emptyList()
if (property.delegate == null) return emptyList()
val getValueSymbol = (property.getter?.singleStatementOfType<FirReturnExpression>()?.result as? FirFunctionCall)?.getCalleeSymbol()
val setValueSymbol = property.setter?.singleStatementOfType<FirFunctionCall>()?.getCalleeSymbol()
return listOfNotNull(
getValueSymbol?.fir?.findPsi(session),
setValueSymbol?.fir?.findPsi(session)
)
}
private inline fun <reified S : FirStatement> FirPropertyAccessor.singleStatementOfType(): S? =
body?.statements?.singleOrNull() as? S
}

View File

@@ -0,0 +1,7 @@
fun kotlin.String.fromString(what: kotlin.Int, oops: kotlin.collections.Map<MyType<kotlin.Boolean>, kotlin.collections.MutableList<kotlin.Boolean>>): kotlin.Unit {}
fun <T : kotlin.Number >kotlin.String.foo(what: kotlin.Int): kotlin.String { TODO() }
fun <T> kotlin.String.withWhere(what: kotlin.Int): T where T : kotlin.Number, T: kotlin.Comparable<kotlin.Number> { TODO() }
class MyType<in F>

View File

@@ -0,0 +1 @@
fun ((kotlin.String) -> kotlin.Int?).foo(other: kotlin.String.() -> kotlin.Unit?): kotlin.Function2<kotlin.Int, kotlin.String, kotlin.Unit> { TODO() }

View File

@@ -0,0 +1,11 @@
class A<S> {
fun x(a: kotlin.Int, b: kotlin.String): Unit {}
fun <T> x(a: kotlin.Int, b: java.lang.String): kotlin.Int { TODO() }
fun <T, Q> x(a: kotlin.collections.Map<T, kotlin.collections.Map<in S, out Q>>, b: kotlin.collections.List<kotlin.Byte>): kotlin.Int { TODO() }
fun <T, Q> kotlin.collections.List<kotlin.collections.Map<T, Q>>.x(f: MyType<S>): kotlin.Int { TODO() }
}
class MyType<in F>

View File

@@ -0,0 +1,37 @@
/*
* 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.idea.fir
import com.intellij.openapi.util.io.FileUtil
import com.intellij.rt.execution.junit.FileComparisonFailure
import junit.framework.Assert
import junit.framework.ComparisonFailure
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.idea.test.KotlinLightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.psiUtil.forEachDescendantOfType
import java.io.File
abstract class AbstractKtDeclarationAndFirDeclarationEqualityChecker : KotlinLightCodeInsightFixtureTestCase() {
protected fun doTest(path: String) {
val file = File(path)
val ktFile = myFixture.configureByText(file.name, FileUtil.loadFile(file)) as KtFile
val resolveState = ktFile.firResolveState()
ktFile.forEachDescendantOfType<KtFunction> { ktFunction ->
val firFunction = ktFunction.getOrBuildFir(resolveState) as FirFunction<*>
if (!KtDeclarationAndFirDeclarationEqualityChecker.representsTheSameDeclaration(ktFunction, firFunction)) {
throw FileComparisonFailure(
/* message= */ null,
KtDeclarationAndFirDeclarationEqualityChecker.renderPsi(ktFunction, firFunction.session),
KtDeclarationAndFirDeclarationEqualityChecker.renderFir(firFunction),
/* expectedFilePath= */ null
)
}
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.idea.fir;
import com.intellij.testFramework.TestDataPath;
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
import org.jetbrains.kotlin.test.KotlinTestUtils;
import org.jetbrains.kotlin.test.TestMetadata;
import org.junit.runner.RunWith;
import java.io.File;
import java.util.regex.Pattern;
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
@SuppressWarnings("all")
@TestMetadata("idea/idea-frontend-fir/testData/ktDeclarationAndFirDeclarationEqualityChecker")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public class KtDeclarationAndFirDeclarationEqualityCheckerGenerated extends AbstractKtDeclarationAndFirDeclarationEqualityChecker {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInKtDeclarationAndFirDeclarationEqualityChecker() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/idea-frontend-fir/testData/ktDeclarationAndFirDeclarationEqualityChecker"), Pattern.compile("^(.+)\\.kt$"), null, true);
}
@TestMetadata("extensionMethods.kt")
public void testExtensionMethods() throws Exception {
runTest("idea/idea-frontend-fir/testData/ktDeclarationAndFirDeclarationEqualityChecker/extensionMethods.kt");
}
@TestMetadata("functionalTypes.kt")
public void testFunctionalTypes() throws Exception {
runTest("idea/idea-frontend-fir/testData/ktDeclarationAndFirDeclarationEqualityChecker/functionalTypes.kt");
}
@TestMetadata("inClass.kt")
public void testInClass() throws Exception {
runTest("idea/idea-frontend-fir/testData/ktDeclarationAndFirDeclarationEqualityChecker/inClass.kt");
}
}

View File

@@ -0,0 +1,41 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
/*
This module should not depend on compiler specific functionality
No dependencies on descriptors (for now we still have transitive one by psi module), fir and similar modules,
but may be dependencies on frontend independent one like psi & type-system
This module is needed for smooth migration from descriptor frontend based IJ plugin to interlayer based one
*/
compileOnly(project(":compiler:frontend")) // we need caches form here to work with ModuleInfo :(
compileOnly(project(":idea:idea-jps-common"))
compileOnly(project(":compiler:psi"))
compileOnly(project(":kotlin-reflect-api"))
compileOnly(intellijCoreDep())
compileOnly(intellijDep())
Platform[191].orLower {
compileOnly(intellijDep()) { includeJars("java-api", "java-impl") }
}
Platform[192].orHigher {
compileOnly(intellijPluginDep("java")) { includeJars("java-api", "java-impl") }
}
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
}
testsJar()
projectTest {
dependsOn(":dist")
workingDir = rootDir
}

View File

@@ -0,0 +1,62 @@
/*
* 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.caches.project
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.openapi.util.UserDataHolder
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
fun <T> Module.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(project).cache(this, dependencies, classForKey, provider)
}
fun <T> Module.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(project), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Module.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
fun <T> Project.cacheByClass(classForKey: Class<*>, vararg dependencies: Any, provider: () -> T): T {
return CachedValuesManager.getManager(this).cache(this, dependencies, classForKey, provider)
}
fun <T> Project.cacheByClassInvalidatingOnRootModifications(classForKey: Class<*>, provider: () -> T): T {
return cacheByClass(classForKey, ProjectRootModificationTracker.getInstance(this), provider = provider)
}
/**
* Note that it uses lambda's class for caching (essentially, anonymous class), which means that all invocations will be cached
* by the one and the same key.
* It is encouraged to use explicit class, just for the sake of readability.
*/
fun <T> Project.cacheInvalidatingOnRootModifications(provider: () -> T): T {
return cacheByClassInvalidatingOnRootModifications(provider::class.java, provider)
}
private fun <T> CachedValuesManager.cache(
holder: UserDataHolder,
dependencies: Array<out Any>,
classForKey: Class<*>,
provider: () -> T
): T {
return getCachedValue(
holder,
getKeyForClass(classForKey),
{ CachedValueProvider.Result.create(provider(), dependencies) },
false
)
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -11,9 +11,7 @@ import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.analyzer.KotlinModificationTrackerService
import org.jetbrains.kotlin.psi.KtFile
class KotlinIDEModificationTrackerService(project: Project) :
KotlinModificationTrackerService() {
class KotlinIDEModificationTrackerService(project: Project) : KotlinModificationTrackerService() {
override val modificationTracker: ModificationTracker = PsiModificationTracker.SERVICE.getInstance(project)
override val outOfBlockModificationTracker: ModificationTracker =

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/

View File

@@ -0,0 +1,24 @@
/*
* 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.idea.core
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.psi.KtParenthesizedExpression
import org.jetbrains.kotlin.psi.KtPsiUtil
inline fun <reified T : PsiElement> PsiElement.replaced(newElement: T): T {
val result = replace(newElement)
return result as? T ?: (result as KtParenthesizedExpression).expression as T
}
//todo make inline
@Suppress("UNCHECKED_CAST")
fun <T : PsiElement> T.copied(): T = copy() as T
fun String.unquote(): String = KtPsiUtil.unquoteIdentifier(this)

View File

@@ -0,0 +1,29 @@
/*
* 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.idea.highlighter
import com.intellij.codeInsight.daemon.impl.HighlightRangeExtension
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.lang.annotation.Annotator
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.psi.KtFile
abstract class AbstractKotlinPsiChecker : Annotator, HighlightRangeExtension {
override fun annotate(element: PsiElement, holder: AnnotationHolder) {
val file = element.containingFile as? KtFile ?: return
if (!shouldHighlight(file)) return
annotateElement(element, file, holder)
}
override fun isForceHighlightParents(file: PsiFile): Boolean {
return file is KtFile
}
protected abstract fun shouldHighlight(file: KtFile): Boolean
protected abstract fun annotateElement(element: PsiElement, containingFile: KtFile, holder: AnnotationHolder)
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.
*/
@@ -16,10 +16,7 @@ import org.jetbrains.kotlin.kdoc.parser.KDocKnownTag
import org.jetbrains.kotlin.kdoc.psi.impl.KDocLink
import org.jetbrains.kotlin.kdoc.psi.impl.KDocTag
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset
@@ -73,7 +70,7 @@ internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : High
val argumentName = argument.getArgumentName() ?: return
val eq = argument.equalsToken ?: return
createInfoAnnotation(TextRange(argumentName.startOffset, eq.endOffset), null).textAttributes =
if(argument.parent.parent is KtAnnotationEntry)
if (argument.parent.parent is KtAnnotationEntry)
KotlinHighlightingColors.ANNOTATION_ATTRIBUTE_NAME_ATTRIBUTES
else
KotlinHighlightingColors.NAMED_ARGUMENT
@@ -85,4 +82,24 @@ internal class BeforeResolveHighlightingVisitor(holder: AnnotationHolder) : High
highlightName(targetLabel, KotlinHighlightingColors.LABEL)
}
}
override fun visitSuperTypeCallEntry(call: KtSuperTypeCallEntry) {
val calleeExpression = call.calleeExpression
val typeElement = calleeExpression.typeReference?.typeElement
if (typeElement is KtUserType) {
typeElement.referenceExpression?.let { highlightName(it, KotlinHighlightingColors.CONSTRUCTOR_CALL) }
}
super.visitSuperTypeCallEntry(call)
}
override fun visitTypeParameter(parameter: KtTypeParameter) {
parameter.nameIdentifier?.let { highlightName(it, KotlinHighlightingColors.TYPE_PARAMETER) }
super.visitTypeParameter(parameter)
}
override fun visitNamedFunction(function: KtNamedFunction) {
highlightNamedDeclaration(function, KotlinHighlightingColors.FUNCTION_DECLARATION)
super.visitNamedFunction(function)
}
}

Some files were not shown because too many files have changed in this diff Show More