Skip to content

Commit

Permalink
Version bump
Browse files Browse the repository at this point in the history
  • Loading branch information
hmemcpy committed Nov 14, 2024
1 parent 6df086b commit 991c1fc
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 47 deletions.
3 changes: 2 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import org.jetbrains.sbtidea.{AutoJbr, JbrPlatform}

lazy val scala213 = "2.13.14"
lazy val scalaPluginVersion = "2024.3.8"
lazy val scalaPluginVersion = "2024.3.18"
lazy val minorVersion = "0"
lazy val buildVersion = sys.env.getOrElse("ZIO_INTELLIJ_BUILD_NUMBER", minorVersion)
lazy val pluginVersion = s"2024.3.35.$buildVersion"
Expand Down Expand Up @@ -64,6 +64,7 @@ def newProject(projectName: String, base: File): Project =
scalaVersion := scala213,
version := pluginVersion,
libraryDependencies ++= Seq(
"junit" % "junit" % "4.13.2" % Test,
"com.github.sbt" % "junit-interface" % "0.13.3" % Test,
"org.junit.jupiter" % "junit-jupiter-api" % "5.11.1" % Test
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,6 @@ object ZStrategy {

override def variableWithoutType(variable: ScVariableDefinition): Boolean = false

override def patternWithoutType(pattern: ScBindingPattern): Boolean = false

override def wildcardPatternWithoutType(pattern: ScWildcardPattern): Boolean = false

override def parameterWithoutType(param: ScParameter): Boolean = false

override def parameterWithType(param: ScParameter): Boolean = false
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package org.jetbrains.plugins.scala.base

import com.intellij.application.options.CodeStyle
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
import com.intellij.codeInsight.daemon.impl.{DaemonCodeAnalyzerImpl, HighlightInfo}
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.module.Module
Expand All @@ -13,12 +14,14 @@ import com.intellij.openapi.util.text.StringUtil
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiFile
import com.intellij.psi.codeStyle.{CodeStyleSettings, CommonCodeStyleSettings}
import com.intellij.testFramework.TestIndexingModeSupporter.IndexingMode
import com.intellij.testFramework.fixtures.{JavaCodeInsightTestFixture, LightJavaCodeInsightFixtureTestCase}
import com.intellij.testFramework.{EditorTestUtil, LightProjectDescriptor}
import com.intellij.testFramework.{EditorTestUtil, IdeaTestUtil, LightProjectDescriptor}
import com.intellij.util.lang.JavaVersion
import org.intellij.lang.annotations.Language
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.plugins.scala.base.libraryLoaders.{LibraryLoader, ScalaSDKLoader, SmartJDKLoader, SourcesLoader}
import org.jetbrains.plugins.scala.extensions.StringExt
import org.jetbrains.plugins.scala.base.libraryLoaders.{LibraryLoader, ScalaSDKLoader, SourcesLoader}
import org.jetbrains.plugins.scala.extensions.{ObjectExt, StringExt}
import org.jetbrains.plugins.scala.lang.formatting.settings.ScalaCodeStyleSettings
import org.jetbrains.plugins.scala.project.settings.ScalaCompilerConfiguration
import org.jetbrains.plugins.scala.util.TestUtils
Expand All @@ -39,23 +42,33 @@ abstract class ScalaLightCodeInsightFixtureTestCase
protected val START = EditorTestUtil.SELECTION_START_TAG
protected val END = EditorTestUtil.SELECTION_END_TAG

protected lazy val scalaFixture: ScalaCodeInsightTestFixture = new ScalaCodeInsightTestFixture(getFixture)
// var is needed to pick up updated java fixture in setUp
private[this] var _scalaFixture: ScalaCodeInsightTestFixture = _
protected def scalaFixture: ScalaCodeInsightTestFixture = _scalaFixture

override def getTestDataPath: String = TestUtils.getTestDataPath + "/"

protected def sourceRootPath: String = null

//start section: indexing mode setup
private[this] var indexingMode: IndexingMode = IndexingMode.SMART

// SCL-21849
override def getIndexingMode: IndexingMode = indexingMode
override def setIndexingMode(mode: IndexingMode): Unit = indexingMode = mode
//end section: indexing mode setup

//start section: project libraries configuration
protected def loadScalaLibrary: Boolean = true

protected def includeReflectLibrary: Boolean = false

protected def includeCompilerAsLibrary: Boolean = false
protected def includeScalaLibrarySources: Boolean = true

protected def additionalLibraries: Seq[LibraryLoader] = Seq.empty

override protected def librariesLoaders: Seq[LibraryLoader] = {
val scalaSdkLoader = ScalaSDKLoader(includeReflectLibrary, includeCompilerAsLibrary)
val scalaSdkLoader = ScalaSDKLoader(includeReflectLibrary, includeCompilerAsLibrary, includeScalaLibrarySources = includeScalaLibrarySources)
//note: do we indeed need to register it as libraries?
// shouldn't source roots be registered just as source roots?
val sourceLoaders = Option(sourceRootPath).map(SourcesLoader).toSeq
Expand All @@ -68,12 +81,14 @@ abstract class ScalaLightCodeInsightFixtureTestCase
protected def sharedProjectToken: SharedTestProjectToken =
SharedTestProjectToken.ByTestClassAndScalaSdkAndProjectLibraries(this)

protected def projectJdk: Sdk = IdeaTestUtil.getMockJdk(JavaVersion.compose(17))

override protected def getProjectDescriptor: LightProjectDescriptor = new ScalaLightProjectDescriptor(sharedProjectToken) {
override def tuneModule(module: Module, project: Project): Unit = {
afterSetUpProject(project, module)
}

override def getSdk: Sdk = SmartJDKLoader.getOrCreateJDK()
override def getSdk: Sdk = projectJdk

override def getSourceRootType: JavaSourceRootType =
if (placeSourceFilesInTestContentRoot)
Expand All @@ -89,14 +104,11 @@ abstract class ScalaLightCodeInsightFixtureTestCase
* test invocations. Look into also overriding [[sharedProjectToken]].
*/
protected def afterSetUpProject(project: Project, module: Module): Unit = {
Registry.get("ast.loading.filter").setValue(true, getTestRootDisposable)

setUpLibraries(module)
}

override def setUpLibraries(implicit module: Module): Unit = {
if (loadScalaLibrary) {
myFixture.allowTreeAccessForAllFiles()
super.setUpLibraries(module)

val compilerOptions = additionalCompilerOptions
Expand Down Expand Up @@ -125,9 +137,24 @@ abstract class ScalaLightCodeInsightFixtureTestCase
//end section: project descriptor

override protected def setUp(): Unit = {
// initialize indexing mode before java test fixture in super.setUp()
/** see also [[com.intellij.testFramework.fixtures.JavaIndexingModeCodeInsightTestFixture]] */
indexingMode = this.findIndexingModeAnnotation()
.fold(IndexingMode.SMART)(_.mode())

super.setUp()
scalaFixture //init fixture lazy val
TestUtils.disableTimerThread()

// pick up updated java fixture after super.setUp()
_scalaFixture = new ScalaCodeInsightTestFixture(getFixture)

// SCL-21849
if (getIndexingMode != IndexingMode.SMART) {
DaemonCodeAnalyzer.getInstance(getProject())
.asOptionOf[DaemonCodeAnalyzerImpl]
.foreach(_.mustWaitForSmartMode(false, getTestRootDisposable))
}

Registry.get("ast.loading.filter").setValue(true, getTestRootDisposable)
}

override protected def tearDown(): Unit = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ import java.{util => ju}
* It doesn't load compiler classpath jars and creates a simple library
*/
final case class ScalaLibraryLoader(
scalaVersion: ScalaVersion,
dependencyManager: DependencyManagerBase = DependencyManager
)
scalaVersion: ScalaVersion,
dependencyManager: DependencyManagerBase = DependencyManager
)
extends LibraryLoader {

import DependencyManagerBase._
Expand Down Expand Up @@ -71,15 +71,15 @@ object ScalaLibraryLoader {
* It uses separate scala libraries with specified versions
*/
def libraryLoadersWithSeparateScalaLibraries(
superLibraryLoaders: Seq[LibraryLoader],
scala2Version: ScalaVersion,
scala3Version: ScalaVersion,
): Seq[LibraryLoader] = {
superLibraryLoaders: Seq[LibraryLoader],
scala2Version: ScalaVersion,
scala3Version: ScalaVersion,
): Seq[LibraryLoader] = {
val scala2LibraryLoader = ScalaLibraryLoader(scala2Version)
val scala3LibraryLoader = ScalaLibraryLoader(scala3Version)

//We use resolveScalaLibraryTransitiveDependencies = false in order to use the latest 2.13.14 RC version
val scala3SdkLoader = ScalaSDKLoader(includeLibraryFilesInSdk = false)
val scala3SdkLoader = ScalaSDKLoader(includeScalaLibraryFilesInSdk = false)

Seq(
scala3LibraryLoader,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,28 @@ import com.intellij.openapi.vfs.{JarFileSystem, VirtualFile}
import com.intellij.testFramework.PsiTestUtil
import org.jetbrains.plugins.scala.extensions.{ObjectExt, inWriteAction}
import org.jetbrains.plugins.scala.project.external.ScalaSdkUtils
import org.jetbrains.plugins.scala.project.{ModuleExt, ScalaLibraryProperties, ScalaLibraryType, template}
import org.jetbrains.plugins.scala.project.{ModuleExt, ScalaLibraryProperties, ScalaLibraryType, Version, template}
import org.jetbrains.plugins.scala.{DependencyManager, DependencyManagerBase, ScalaVersion}
import org.junit.Assert._

import java.io.File
import java.{util => ju}

/** @param includeScalaReflectIntoCompilerClasspath also see [[ScalaReflectLibraryLoader]] */
/**
* @param includeScalaReflectIntoCompilerClasspath also see [[ScalaReflectLibraryLoader]]
* @param includeScalaLibraryTransitiveDependencies for scala 3 library, also includes scala 2 library
*/
case class ScalaSDKLoader(
includeScalaReflectIntoCompilerClasspath: Boolean = false,
//TODO: drop this parameter and fix tests
includeScalaCompilerIntoLibraryClasspath: Boolean = false,
includeLibraryFilesInSdk: Boolean = true,
compilerBridgeBinaryJar: Option[File] = None,
dependencyManager: DependencyManagerBase = DependencyManager
) extends LibraryLoader {
includeScalaReflectIntoCompilerClasspath: Boolean = false,
//TODO: drop this parameter and fix tests
includeScalaCompilerIntoLibraryClasspath: Boolean = false,
includeScalaLibraryTransitiveDependencies: Boolean = true,
includeScalaLibraryFilesInSdk: Boolean = true,
//TODO: by default sources are not needed in all tests
// make it "false" by default, check which tests fail and set it to true in those tests
includeScalaLibrarySources: Boolean = true,
compilerBridgeBinaryJar: Option[File] = None,
dependencyManager: DependencyManagerBase = DependencyManager
) extends LibraryLoader {

import DependencyManagerBase._
import ScalaSDKLoader._
Expand All @@ -39,7 +45,7 @@ case class ScalaSDKLoader(
if (version.languageLevel.isScala3) {
List(
scalaCompilerDescription.transitive(),
scalaLibraryDescription.transitive(),
if (includeScalaLibraryTransitiveDependencies) scalaLibraryDescription.transitive() else scalaLibraryDescription,
DependencyDescription("org.scala-lang", "scala3-interfaces", version.minor),
)
}
Expand All @@ -51,12 +57,27 @@ case class ScalaSDKLoader(
) ++ maybeScalaReflect
}

protected def sourcesDependency(implicit version: ScalaVersion): DependencyDescription =
scalaLibraryDescription % Types.SRC
/**
* Resolves scala library sources for a given version and returns it's jars.
* For Scala 3 version it returns two roots - for Scala 2 and Scala 3 libraries
*/
final def scalaLibrarySources(implicit version: ScalaVersion): Seq[VirtualFile] = {
val sourceDependency = scalaLibraryDescription % Types.SRC
val sourceDependencyActual = if (includeScalaLibraryTransitiveDependencies) sourceDependency.transitive() else sourceDependency

val resolved = dependencyManager.resolve(sourceDependencyActual)
// This second pass is necessary to resolve Scala 2 library sources, when it's a transitive dependency of a Scala 3 library.
// For some reason, if I tell Ivy to download dependency sources and set transitive="true" it doesn't download sources for transitive dependencies.
// Instead, it downloads regular class file jars.
// As a workaround, I do another pass where I download sources for each such class files jar file independently, non-transitively.
val resolvedSecondPass = if (resolved.size == 1) resolved else resolved.map(_.info).map(d => dependencyManager.resolveSingle(d.sources()))
resolvedSecondPass.map(_.file).map(findJarFile)
}

final def sourceRoot(implicit version: ScalaVersion): VirtualFile = {
val ResolvedDependency(_, file) = dependencyManager.resolveSingle(sourcesDependency)
findJarFile(file)
private def resolveCompilerBridge(version: ScalaVersion): Option[File] = {
if (version >= ScalaVersion.fromString("2.13.12").get)
ScalaSdkUtils.resolveCompilerBridgeJar(version.minor)
else None
}

override final def init(implicit module: Module, version: ScalaVersion): Unit = {
Expand All @@ -79,7 +100,7 @@ case class ScalaSDKLoader(
val compilerClasspath = resolvedOk.map(_.file)

// Manually resolve a compiler bridge only if it hasn't been provided. This allows testing with a custom bridge.
val compilerBridge = compilerBridgeBinaryJar.orElse(ScalaSdkUtils.resolveCompilerBridgeJar(version.minor))
val compilerBridge = compilerBridgeBinaryJar.orElse(resolveCompilerBridge(version))

assertTrue(
s"Some SDK jars were resolved but for some reason do not exist:\n$resolvedMissing",
Expand All @@ -95,16 +116,16 @@ case class ScalaSDKLoader(
}

val scalaLibraryClasses: Seq[VirtualFile] =
if (includeLibraryFilesInSdk) {
if (includeScalaLibraryFilesInSdk) {
val files =
if (includeScalaCompilerIntoLibraryClasspath) compilerClasspath
else compilerClasspath.filter(_.getName.matches(".*(scala-library|scala3-library).*"))
files.map(findJarFile)
}
else Nil

val scalaLibrarySources =
if (includeLibraryFilesInSdk) Seq(sourceRoot)
val scalaLibrarySourcesActual: Seq[VirtualFile] =
if (includeScalaLibrarySources) scalaLibrarySources
else Nil

val libraryTable = LibraryTablesRegistrar.getInstance.getLibraryTable(module.getProject)
Expand All @@ -117,7 +138,7 @@ case class ScalaSDKLoader(
module,
scalaSdkName,
scalaLibraryClasses.asJava,
scalaLibrarySources.asJava
scalaLibrarySourcesActual.asJava
)

val library =
Expand Down
35 changes: 35 additions & 0 deletions src/test/scala/org/jetbrains/plugins/scala/base/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.jetbrains.plugins.scala

import _root_.junit.framework.TestCase
import org.jetbrains.plugins.scala.extensions.ObjectExt
import org.jetbrains.plugins.scala.util.NotNothing
import org.jetbrains.plugins.scala.util.runners.WithIndexingMode

import java.lang.annotation.Annotation
import scala.reflect.{ClassTag, classTag}
import scala.util.Try

package object base {
final implicit class TestCaseExt(private val testCase: TestCase) extends AnyVal {
// SCL-21849
def findIndexingModeAnnotation(): Option[WithIndexingMode] = findTestAnnotation[WithIndexingMode]

/**
* Tries to find the specified annotation on the current test method and then on the current class.
* And then on the superclass if marked as [[java.lang.annotation.Inherited]].
*/
def findTestAnnotation[A <: Annotation : ClassTag : NotNothing]: Option[A] =
testMethodAnnotation[A].orElse(classAnnotation[A])

private def testMethodAnnotation[A <: Annotation : ClassTag]: Option[A] =
for {
name <- testCase.getName.toOption
// java.lang.NoSuchMethodException can happen in generated tests (e.g.: FileSetTests)
method <- Try(testCase.getClass.getMethod(name)).toOption
annotation <- method.getAnnotation(classTag[A].runtimeClass.asInstanceOf[Class[A]]).toOption
} yield annotation

private def classAnnotation[A <: Annotation : ClassTag]: Option[A] =
testCase.getClass.getAnnotation(classTag[A].runtimeClass.asInstanceOf[Class[A]]).toOption
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.jetbrains.plugins.scala.util.runners;

import com.intellij.testFramework.TestIndexingModeSupporter.IndexingMode;

import java.lang.annotation.*;

/**
* Enables one of the indexing modes for each test: smart mode or dumb mode with empty, partial or full index.
*
* @see IndexingMode
* @see org.jetbrains.plugins.scala.base.ScalaLightCodeInsightFixtureTestCase
* @see <a href="https://youtrack.jetbrains.com/issue/SCL-21849/Make-more-functionality-available-during-indexing">SCL-21849</a>
* @see <a href="https://youtrack.jetbrains.com/articles/IJPL-A-270/Make-functionality-available-during-indexing">Make functionality available during indexing</a>
*/
@Inherited
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface WithIndexingMode {
IndexingMode mode();

String reason() default "";
}

0 comments on commit 991c1fc

Please sign in to comment.