[FE] Support analyzable files throughout all 'KtPsiFactory' API

Before, the only way of getting analyzable elements was to create an
analyzable file by using 'createAnalyzableFile()'. So made all utilities
available in 'KtPsiFactory' useless as they delegate to 'createFile()'
that always set the 'doNotAnalyze' flag.

The new behavior is to pass the 'analysisContext' instead if it is
passed to the 'KtPsiFactory' constructor.

The newly appeared API is going to be used in the Kotlin's UAST
implementation.
This commit is contained in:
Yan Zhulanow
2022-10-04 02:15:30 +09:00
committed by teamcity
parent f3c4ae8bbf
commit ea3f550b58
37 changed files with 102 additions and 86 deletions
@@ -45,7 +45,7 @@ object EditCommaSeparatedListHelper {
list.add(item) as TItem
}
} else {
var comma = KtPsiFactory(list).createComma()
var comma = KtPsiFactory(list.project).createComma()
return if (anchor != null) {
comma = list.addAfter(comma, anchor)
list.addAfter(item, comma) as TItem
@@ -53,7 +53,7 @@ abstract class KtClassOrObject :
return EditCommaSeparatedListHelper.addItem(it, superTypeListEntries, superTypeListEntry)
}
val psiFactory = KtPsiFactory(this)
val psiFactory = KtPsiFactory(project)
val specifierListToAdd = psiFactory.createSuperTypeCallEntry("A()").replace(superTypeListEntry).parent
val colon = addBefore(psiFactory.createColon(), getBody())
return (addAfter(specifierListToAdd, colon) as KtSuperTypeList).entries.first()
@@ -202,7 +202,7 @@ abstract class KtClassOrObject :
fun KtClassOrObject.getOrCreateBody(): KtClassBody {
getBody()?.let { return it }
val newBody = KtPsiFactory(this).createEmptyClassBody()
val newBody = KtPsiFactory(project).createEmptyClassBody()
if (this is KtEnumEntry) return addAfter(newBody, initializerList ?: nameIdentifier) as KtClassBody
return add(newBody) as KtClassBody
}
@@ -151,7 +151,7 @@ abstract class KtCodeFragment(
fun importsAsImportList(): KtImportList? {
if (imports.isNotEmpty() && context != null) {
return KtPsiFactory(this).createAnalyzableFile("imports_for_codeFragment.kt", imports.joinToString("\n"), context).importList
return KtPsiFactory.contextual(context).createFile("imports_for_codeFragment.kt", imports.joinToString("\n")).importList
}
return null
}
@@ -35,15 +35,14 @@ abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtExpressi
when (parent) {
is KtExpression, is KtValueArgument -> {
if (KtPsiUtil.areParenthesesNecessary(newElement, expression, parent as KtElement)) {
return rawReplaceHandler(
KtPsiFactory(expression).createExpressionByPattern("($0)", newElement, reformat = reformat)
)
val factory = KtPsiFactory(expression.project)
return rawReplaceHandler(factory.createExpressionByPattern("($0)", newElement, reformat = reformat))
}
}
is KtSimpleNameStringTemplateEntry -> {
if (newElement !is KtSimpleNameExpression && !newElement.isThisWithoutLabel()) {
val newEntry =
parent.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(newElement)) as KtBlockStringTemplateEntry
val factory = KtPsiFactory(expression.project)
val newEntry = parent.replace(factory.createBlockStringTemplateEntry(newElement)) as KtBlockStringTemplateEntry
return newEntry.expression!!
}
}
@@ -94,7 +94,7 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) :
if (packageDirective != null) {
packageDirective.fqName = value
} else {
val newPackageDirective = KtPsiFactory(this).createPackageDirectiveIfNeeded(value) ?: return
val newPackageDirective = KtPsiFactory(project).createPackageDirectiveIfNeeded(value) ?: return
addAfter(newPackageDirective, null)
}
}
@@ -39,7 +39,7 @@ class KtImportAlias : KtElementImplStub<KotlinImportAliasStub>, PsiNameIdentifie
override fun getName() = stub?.getName() ?: nameIdentifier?.text
override fun setName(name: String): PsiElement {
nameIdentifier?.replace(KtPsiFactory(this).createNameIdentifier(name))
nameIdentifier?.replace(KtPsiFactory(project).createNameIdentifier(name))
return this
}
@@ -45,7 +45,7 @@ public class KtImportsFactory {
return directive;
}
KtImportDirective createdDirective = KtPsiFactoryKt.KtPsiFactory(project, false).createImportDirective(importPath);
KtImportDirective createdDirective = new KtPsiFactory(project, false).createImportDirective(importPath);
importsCache.put(importPath, createdDirective);
return createdDirective;
@@ -58,6 +58,6 @@ public class KtImportsFactory {
@NotNull
public Collection<KtImportDirective> createImportDirectivesNotCached(@NotNull Collection<ImportPath> importPaths) {
return KtPsiFactoryKt.KtPsiFactory(project, false).createImportDirectives(importPaths);
return new KtPsiFactory(project, false).createImportDirectives(importPaths);
}
}
@@ -24,8 +24,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.lexer.KtTokens;
import static org.jetbrains.kotlin.psi.KtPsiFactoryKt.KtPsiFactory;
// TODO: Remove when all named declarations get stubs
@Deprecated
abstract class KtNamedDeclarationNotStubbed extends KtDeclarationImpl implements KtNamedDeclaration {
@@ -67,7 +65,7 @@ abstract class KtNamedDeclarationNotStubbed extends KtDeclarationImpl implements
PsiElement identifier = getNameIdentifier();
if (identifier == null) throw new IncorrectOperationException();
return identifier.replace(KtPsiFactory(this).createNameIdentifier(name));
return identifier.replace(new KtPsiFactory(getProject()).createNameIdentifier(name));
}
@Override
@@ -32,8 +32,6 @@ import org.jetbrains.kotlin.util.OperatorNameConventions;
import java.util.Set;
import static org.jetbrains.kotlin.psi.KtPsiFactoryKt.KtPsiFactory;
abstract class KtNamedDeclarationStub<T extends KotlinStubWithFqName<?>> extends KtDeclarationStub<T> implements KtNamedDeclaration {
public KtNamedDeclarationStub(@NotNull T stub, @NotNull IStubElementType nodeType) {
super(stub, nodeType);
@@ -99,8 +97,7 @@ abstract class KtNamedDeclarationStub<T extends KotlinStubWithFqName<?>> extends
}
}
PsiElement newIdentifier =
KtPsiFactory(this).createNameIdentifierIfPossible(KtPsiUtilKt.quoteIfNeeded(name));
PsiElement newIdentifier = new KtPsiFactory(getProject()).createNameIdentifierIfPossible(KtPsiUtilKt.quoteIfNeeded(name));
if (newIdentifier != null) {
KtPsiUtilKt.astReplace(identifier, newIdentifier);
}
@@ -34,7 +34,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
override fun getContainingClassOrObject() = parent as KtClassOrObject
private fun getOrCreateConstructorKeyword(): PsiElement {
return getConstructorKeyword() ?: addBefore(KtPsiFactory(this).createConstructorKeyword(), valueParameterList!!)
return getConstructorKeyword() ?: addBefore(KtPsiFactory(project).createConstructorKeyword(), valueParameterList!!)
}
fun removeRedundantConstructorKeywordAndSpace() {
@@ -53,7 +53,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
}
} else {
if (modifier == KtTokens.PUBLIC_KEYWORD) return
val newModifierList = KtPsiFactory(this).createModifierList(modifier)
val newModifierList = KtPsiFactory(project).createModifierList(modifier)
addBefore(newModifierList, getOrCreateConstructorKeyword())
}
}
@@ -21,14 +21,19 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.psiUtil.isIdentifier
import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
import org.jetbrains.kotlin.utils.checkWithAttachment
@JvmOverloads
fun KtPsiFactory(project: Project?, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(project!!, markGenerated)
@JvmName("KtPsiFactory")
@Suppress("FunctionName", "unused")
@Deprecated("Use 'KtPsiFactory' constructor instead", level = DeprecationLevel.HIDDEN)
fun KtPsiFactoryOld(project: Project?, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(project!!, markGenerated)
@JvmOverloads
fun KtPsiFactory(elementForProject: PsiElement, markGenerated: Boolean = true): KtPsiFactory =
@JvmName("KtPsiFactory")
@Suppress("FunctionName", "unused")
@Deprecated("Use 'KtPsiFactory' constructor instead", level = DeprecationLevel.HIDDEN)
fun KtPsiFactoryOld(elementForProject: PsiElement, markGenerated: Boolean = true): KtPsiFactory =
KtPsiFactory(elementForProject.project, markGenerated)
private const val DO_NOT_ANALYZE_NOTIFICATION = "This file was created by KtPsiFactory and should not be analyzed\n" +
@@ -43,7 +48,25 @@ var KtFile.analysisContext: PsiElement? by UserDataProperty(Key.create("ANALYSIS
* to be inserted in the user source code (this ensures that the elements will be formatted correctly). In other cases, `markGenerated`
* should be false, which saves time and memory.
*/
class KtPsiFactory @JvmOverloads constructor(private val project: Project, val markGenerated: Boolean = true) {
class KtPsiFactory private constructor(
private val project: Project,
private val markGenerated: Boolean,
private val context: PsiElement?
) {
companion object {
@JvmStatic
@JvmOverloads
fun contextual(context: PsiElement, markGenerated: Boolean = true): KtPsiFactory {
return KtPsiFactory(context.project, markGenerated, context)
}
}
@JvmOverloads
constructor(project: Project, markGenerated: Boolean = true) : this(project, markGenerated, context = null)
@JvmOverloads
@Deprecated("Use 'KtPsiFactory(project, markGenerated)' or 'KtPsiFactory.contextual(context, markGenerated)' instead")
constructor(element: KtElement, markGenerated: Boolean = true) : this(element.project, markGenerated, context = null)
fun createValKeyword(): PsiElement {
val property = createProperty("val x = 1")
@@ -217,17 +240,24 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
fun createFile(@NonNls fileName: String, @NonNls text: String): KtFile {
val file = doCreateFile(fileName, text)
file.doNotAnalyze = DO_NOT_ANALYZE_NOTIFICATION
val analysisContext = this@KtPsiFactory.context
if (analysisContext != null) {
file.analysisContext = analysisContext
} else {
file.doNotAnalyze = DO_NOT_ANALYZE_NOTIFICATION
}
return file
}
@Deprecated("Call 'createFile()' on a contextual 'KtPsiFactory' instead")
fun createAnalyzableFile(@NonNls fileName: String, @NonNls text: String, contextToAnalyzeIn: PsiElement): KtFile {
val file = doCreateFile(fileName, text)
file.analysisContext = contextToAnalyzeIn
return file
}
@Deprecated("Call 'createPhysicalFile() on a contextual 'KtPsiFactory' instead")
fun createFileWithLightClassSupport(@NonNls fileName: String, @NonNls text: String, contextToAnalyzeIn: PsiElement): KtFile {
val file = createPhysicalFile(fileName, text)
file.analysisContext = contextToAnalyzeIn
@@ -235,13 +265,10 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
}
fun createPhysicalFile(@NonNls fileName: String, @NonNls text: String): KtFile {
return PsiFileFactory.getInstance(project).createFileFromText(
fileName,
KotlinFileType.INSTANCE,
text,
LocalTimeCounter.currentTime(),
true
) as KtFile
val time = LocalTimeCounter.currentTime()
val file = PsiFileFactory.getInstance(project).createFileFromText(fileName, KotlinFileType.INSTANCE, text, time, true) as KtFile
file.analysisContext = this@KtPsiFactory.context
return file
}
fun createProperty(
@@ -22,7 +22,7 @@ private fun KtModifierListOwner.addModifierList(newModifierList: KtModifierList)
}
private fun createModifierList(text: String, owner: KtModifierListOwner): KtModifierList {
return owner.addModifierList(KtPsiFactory(owner).createModifierList(text))
return owner.addModifierList(KtPsiFactory(owner.project).createModifierList(text))
}
fun KtModifierListOwner.setModifierList(newModifierList: KtModifierList) {
@@ -55,7 +55,7 @@ fun addAnnotationEntry(owner: KtModifierListOwner, annotationEntry: KtAnnotation
internal fun addModifier(modifierList: KtModifierList, modifier: KtModifierKeywordToken) {
if (modifierList.hasModifier(modifier)) return
val newModifier = KtPsiFactory(modifierList).createModifier(modifier)
val newModifier = KtPsiFactory(modifierList.project).createModifier(modifier)
val modifierToReplace = MODIFIERS_TO_REPLACE[modifier]
?.mapNotNull { modifierList.getModifier(it) }
?.firstOrNull()
@@ -113,7 +113,7 @@ fun removeModifier(owner: KtModifierListOwner, modifier: KtModifierKeywordToken)
val lastChild = it.lastChild
if (lastChild is PsiComment) {
it.addAfter(KtPsiFactory(owner).createNewLine(), lastChild)
it.addAfter(KtPsiFactory(owner.project).createNewLine(), lastChild)
}
}
}
@@ -548,7 +548,7 @@ fun isDoubleColonReceiver(expression: KtExpression) =
fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
valueParameterList?.let { return it }
val psiFactory = KtPsiFactory(this)
val psiFactory = KtPsiFactory(project)
val anchor = lBrace
val newParameterList = addAfter(psiFactory.createLambdaParameterList("x"), anchor) as KtParameterList
@@ -589,7 +589,7 @@ fun KtFunctionLiteral.findLabelAndCall(): Pair<Name?, KtCallExpression?> {
fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList {
valueArgumentList?.let { return it }
return addAfter(
KtPsiFactory(this).createCallArguments("()"),
KtPsiFactory(project).createCallArguments("()"),
typeArgumentList ?: calleeExpression,
) as KtValueArgumentList
}
@@ -598,7 +598,7 @@ fun KtCallExpression.addTypeArgument(typeArgument: KtTypeProjection) {
if (typeArgumentList != null) {
typeArgumentList?.addArgument(typeArgument)
} else {
addAfter(KtPsiFactory(this).createTypeArguments("<${typeArgument.text}>"), calleeExpression)
addAfter(KtPsiFactory(project).createTypeArguments("<${typeArgument.text}>"), calleeExpression)
}
}