Skip to content

Commit 72de1ec

Browse files
author
builduser
committed
Merged branch idea251.release into idea251.x
2 parents 18a5737 + 31eebdb commit 72de1ec

File tree

6 files changed

+94
-22
lines changed

6 files changed

+94
-22
lines changed

scala/scala-impl/src/org/jetbrains/plugins/scala/lang/formatting/scalafmt/processors/ScalaFmtPreFormatProcessor.scala

+32-22
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import com.intellij.psi.javadoc.PsiDocComment
1818
import com.intellij.psi.util.PsiTreeUtil
1919
import org.apache.commons.lang3.StringUtils
2020
import org.jetbrains.annotations.{NonNls, TestOnly}
21+
import org.jetbrains.plugins.scala.ScalaBundle
2122
import org.jetbrains.plugins.scala.extensions.{PsiElementExt, _}
2223
import org.jetbrains.plugins.scala.lang.formatting.scalafmt.processors.PsiChange._
2324
import org.jetbrains.plugins.scala.lang.formatting.scalafmt.processors.ScalaFmtPreFormatProcessor._
@@ -38,9 +39,8 @@ import org.jetbrains.plugins.scala.lang.psi.impl.ScalaPsiElementFactory
3839
import org.jetbrains.plugins.scala.lang.psi.impl.expr.ScBlockImpl
3940
import org.jetbrains.plugins.scala.lang.psi.{ScalaPsiUtil, TypeAdjuster}
4041
import org.jetbrains.plugins.scala.lang.scaladoc.psi.api.ScDocComment
41-
import org.jetbrains.plugins.scala.project.UserDataHolderExt
42+
import org.jetbrains.plugins.scala.project.{ScalaFeatures, UserDataHolderExt}
4243
import org.jetbrains.plugins.scala.scalaMeta.ScalaMetaParseException
43-
import org.jetbrains.plugins.scala.{ScalaBundle, ScalaFileType}
4444
import org.scalafmt.dynamic.exceptions.{PositionExceptionImpl, ReflectionException}
4545
import org.scalafmt.dynamic.{ScalafmtReflect, ScalafmtReflectConfig, ScalafmtVersion}
4646

@@ -49,6 +49,7 @@ import javax.swing.event.HyperlinkEvent
4949
import scala.annotation.{nowarn, tailrec}
5050
import scala.collection.immutable.ArraySeq
5151
import scala.collection.mutable
52+
import scala.jdk.CollectionConverters.CollectionHasAsScala
5253
import scala.util.Try
5354
import scala.util.control.NonFatal
5455
import scala.util.matching.Regex
@@ -422,7 +423,7 @@ object ScalaFmtPreFormatProcessor {
422423
}
423424
}
424425

425-
def processRange(elements: Seq[PsiElement], wrap: Boolean, typeAdjuster: TypeAdjuster): Either[Unit, Int] = {
426+
def processRange(elements: Seq[PsiElement], features: ScalaFeatures, wrap: Boolean, typeAdjuster: TypeAdjuster): Either[Unit, Int] = {
426427
val hasRewriteRules = context.config.hasRewriteRules
427428
val rewriteElements: Seq[PsiElement] = if (hasRewriteRules) elements.flatMap(maybeRewriteElements(_, range)) else Seq.empty
428429
val rewriteElementsToFormatted = attachFormattedCode(rewriteElements)
@@ -433,7 +434,7 @@ object ScalaFmtPreFormatProcessor {
433434
val formattedInSingleFile = formatInSingleFile(elements, wrap)(project, newContext)
434435
formattedInSingleFile match {
435436
case Some(formatted) =>
436-
replaceWithFormatted(elements, formatted, rewriteElementsToFormatted, range, typeAdjuster) match {
437+
replaceWithFormatted(elements, formatted, rewriteElementsToFormatted, features, range, typeAdjuster) match {
437438
case Left(err) =>
438439
reportMarkerNotFound(file, err)
439440
Left(())
@@ -455,11 +456,11 @@ object ScalaFmtPreFormatProcessor {
455456
Left(())
456457
} else {
457458
//failed to wrap some elements, try the whole file
458-
processRange(Seq(file), wrap = false, typeAdjuster).map(Some(_))
459+
processRange(Seq(file), file.features, wrap = false, typeAdjuster).map(Some(_))
459460
Right(None)
460461
}
461462
} else {
462-
processRange(elementsWrapped, wrap = true, typeAdjuster).map(Some(_))
463+
processRange(elementsWrapped, file.features, wrap = true, typeAdjuster).map(Some(_))
463464
}
464465
}
465466

@@ -478,23 +479,29 @@ object ScalaFmtPreFormatProcessor {
478479
private def getText(range: TextRange)(implicit fileText: String): String =
479480
fileText.substring(range.getStartOffset, range.getEndOffset)
480481

481-
private def unwrap(wrapFile: PsiFile)(implicit project: Project): Either[CantFindMarkerElementInFormattedCode, Seq[PsiElement]] = {
482+
private def unwrap(wrapFile: ScalaFile)(implicit project: Project): Either[CantFindMarkerElementInFormattedCode, Seq[PsiElement]] = {
482483
val text = wrapFile.getText
483484

484485
val startMarkerIdx = findMarker(text, StartMarkerFormattedRegex)
485486
// I don't know when it can be the case that start/end element are null, but handling it just to avoid exceptions
486-
val startElement = wrapFile.findElementAt(startMarkerIdx)
487-
if (startElement == null)
488-
return Left(CantFindMarkerElementInFormattedCode(true))
487+
if (startMarkerIdx == -1)
488+
return Left(CantFindMarkerElementInFormattedCode(isStartMarker = true))
489489

490490
val endMarkerIdx = findMarker(text, EndMarkerFormattedRegex)
491-
val endElement = wrapFile.findElementAt(endMarkerIdx)
492-
if (endElement == null)
493-
return Left(CantFindMarkerElementInFormattedCode(true))
491+
if (endMarkerIdx == -1)
492+
return Left(CantFindMarkerElementInFormattedCode(isStartMarker = false))
494493

495-
// we need to call extra `getParent` because findElementAt returns DOC_COMMENT_START
496-
val startMarker = startElement.getParent
497-
val endMarker = endElement.getParent
494+
val docComments = PsiTreeUtil.findChildrenOfType(wrapFile, classOf[ScDocComment]).asScala
495+
496+
val startMarker = docComments.find(e => e.getTextOffset == startMarkerIdx && StartMarkerFormattedRegex.matches(e.getText)) match {
497+
case None => return Left(CantFindMarkerElementInFormattedCode(isStartMarker = true))
498+
case Some(marker) => marker
499+
}
500+
501+
val endMarker = docComments.find(e => e.getTextOffset == endMarkerIdx && EndMarkerFormattedRegex.matches(e.getText)) match {
502+
case None => return Left(CantFindMarkerElementInFormattedCode(isStartMarker = false))
503+
case Some(marker) => marker
504+
}
498505

499506
assert(startMarker.is[ScDocComment])
500507
assert(endMarker.is[ScDocComment])
@@ -664,9 +671,10 @@ object ScalaFmtPreFormatProcessor {
664671
}
665672

666673
private def unwrapPsiFromFormattedFile(
667-
formattedCode: WrappedCode
674+
formattedCode: WrappedCode,
675+
features: ScalaFeatures
668676
)(implicit project: Project): Either[CantFindMarkerElementInFormattedCode, RewriteElements] = {
669-
val wrapFile = PsiFileFactory.getInstance(project).createFileFromText(DummyWrapperClassName, ScalaFileType.INSTANCE, formattedCode.text)
677+
val wrapFile = ScalaPsiElementFactory.createScalaFileFromText(formattedCode.text, features, shouldTrimText = false)
670678
val elementsUnwrapped: Either[CantFindMarkerElementInFormattedCode, Seq[PsiElement]] =
671679
if (formattedCode.wrapped) unwrap(wrapFile)
672680
else Right(Seq(wrapFile))
@@ -676,10 +684,11 @@ object ScalaFmtPreFormatProcessor {
676684
}
677685

678686
private def unwrapPsiFromFormattedElements(
679-
elementsToFormatted: Seq[(PsiElement, WrappedCode)]
687+
elementsToFormatted: Seq[(PsiElement, WrappedCode)],
688+
features: ScalaFeatures
680689
)(implicit project: Project): Seq[(PsiElement, Either[CantFindMarkerElementInFormattedCode, RewriteElements])] = {
681690
val withUnwrapped = elementsToFormatted.map { case (element, formattedCode) =>
682-
val unwrapped = unwrapPsiFromFormattedFile(formattedCode)
691+
val unwrapped = unwrapPsiFromFormattedFile(formattedCode, features)
683692
(element, unwrapped)
684693
}
685694
withUnwrapped.sortBy(_._1.getTextRange.getStartOffset)
@@ -688,18 +697,19 @@ object ScalaFmtPreFormatProcessor {
688697
private def replaceWithFormatted(elements: Iterable[PsiElement],
689698
formattedCode: WrappedCode,
690699
rewriteToFormatted: Seq[(PsiElement, WrappedCode)],
700+
features: ScalaFeatures,
691701
range: TextRange,
692702
typeAdjuster: TypeAdjuster)
693703
(implicit project: Project, fileText: String): Either[CantFindMarkerElementInFormattedCode, Int] = {
694-
val elementsUnwrapped: Seq[PsiElement] = unwrapPsiFromFormattedFile(formattedCode) match {
704+
val elementsUnwrapped: Seq[PsiElement] = unwrapPsiFromFormattedFile(formattedCode, features) match {
695705
case Right(value) =>
696706
value.elements
697707
case Left(err) =>
698708
return Left(err)
699709
}
700710
val elementsToTraverse: Iterable[(PsiElement, PsiElement)] = elements.zip(elementsUnwrapped)
701711
val rewriteElementsToTraverse0: Seq[(PsiElement, Either[CantFindMarkerElementInFormattedCode, RewriteElements])] =
702-
unwrapPsiFromFormattedElements(rewriteToFormatted)
712+
unwrapPsiFromFormattedElements(rewriteToFormatted, features)
703713

704714
rewriteElementsToTraverse0.find(_._2.isLeft) match {
705715
case Some((_, Left(err))) =>

scala/scala-impl/test/org/jetbrains/plugins/scala/lang/optimize/generated/OptimizeImportsWithScalafmtFormatter.scala

+19
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,22 @@ final class OptimizeImportsWithScalafmtFormatterWithLibraries extends OptimizeIm
9191
doTest()
9292
}
9393
}
94+
95+
class OptimizeImportsWithScalafmtFormatterRenamedImportsSource3 extends OptimizeImportsWithScalafmtFormatterBase {
96+
override protected def scalafmtVersion: String = "3.8.3"
97+
98+
def testSCL23689_NoChange(): Unit = runSCL23689Test()
99+
100+
def testSCL23689_Optimize(): Unit = runSCL23689Test()
101+
102+
private def runSCL23689Test(): Unit = RevertableChange.withCompilerSettingsModified(
103+
getModule,
104+
s => s.copy(additionalCompilerOptions = s.additionalCompilerOptions :+ "-Xsource:3")
105+
) {
106+
scalaCodeStyleSettings.SCALAFMT_USE_INTELLIJ_FORMATTER_FOR_RANGE_FORMAT = false
107+
doTest()
108+
109+
scalaCodeStyleSettings.SCALAFMT_USE_INTELLIJ_FORMATTER_FOR_RANGE_FORMAT = true
110+
doTest()
111+
}
112+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Notification message: null
2+
package example.bug
3+
4+
import java.lang as la
5+
import scala.concurrent.Future
6+
7+
class TestImports {
8+
def clientStateSurface(): Future[la.String] = ???
9+
}
10+
/*package example.bug
11+
12+
import java.lang as la
13+
import scala.concurrent.Future
14+
15+
class TestImports {
16+
def clientStateSurface(): Future[la.String] = ???
17+
}
18+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version = "3.8.3"
2+
runner.dialect = scala3
3+
rewrite.trailingCommas.style = keep // `[`https://scalameta.org/scalafmt/docs/configuration.html#trailing-commas`](https://scalameta.org/scalafmt/docs/configuration.html#trailing-commas)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Notification message: Removed 2 imports, added 1 import
2+
package example.bug
3+
4+
import java.lang as la
5+
import scala.concurrent.Future
6+
import java.util.concurrent.CompletableFuture
7+
8+
class TestImports {
9+
def clientStateSurface(): Future[la.String] = ???
10+
}
11+
/*package example.bug
12+
13+
import java.lang as la
14+
import scala.concurrent.Future
15+
16+
class TestImports {
17+
def clientStateSurface(): Future[la.String] = ???
18+
}
19+
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version = "3.8.3"
2+
runner.dialect = scala3
3+
rewrite.trailingCommas.style = keep // `[`https://scalameta.org/scalafmt/docs/configuration.html#trailing-commas`](https://scalameta.org/scalafmt/docs/configuration.html#trailing-commas)

0 commit comments

Comments
 (0)