Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

re #1000631. Adding a classpath validator. Initial commit. Breaks Sbt…

…BuilderTest@dependencyTest.

Added validator methods to ScalaProject.
Added link for Java Model listener to validator when classpath is modified in ScalaPlugin.
Added check if project classpath is valid in ScalaBuilder.
Added set of tests for different configuration of the classpath.
  • Loading branch information...
commit 809cf3ba02331dd03fe1c715e4296b1b47cfd645 1 parent 17cdf11
@skyluc skyluc authored
Showing with 446 additions and 40 deletions.
  1. +3 −1 org.scala-ide.sdt.core.tests/src/scala/tools/eclipse/TestsSuite.java
  2. +244 −0 org.scala-ide.sdt.core.tests/src/scala/tools/eclipse/classpath/ClasspathTests.scala
  3. +7 −0 org.scala-ide.sdt.core.tests/test-workspace/classpath/.classpath
  4. +18 −0 org.scala-ide.sdt.core.tests/test-workspace/classpath/.project
  5. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.10.x/my-scala-library.jar
  6. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.10.x/scala-library.jar
  7. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.8.x/my-scala-library.jar
  8. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.8.x/scala-library.jar
  9. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.9.x/my-scala-library.jar
  10. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.9.x/scala-library.jar
  11. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/noproperties/scala-library.jar
  12. BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/noversion/scala-library.jar
  13. +12 −0 org.scala-ide.sdt.core.tests/test-workspace/classpath/src/test/Test.scala
  14. +12 −13 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaBuilder.scala
  15. +23 −6 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPlugin.scala
  16. +127 −20 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaProject.scala
View
4 org.scala-ide.sdt.core.tests/src/scala/tools/eclipse/TestsSuite.java
@@ -1,5 +1,6 @@
package scala.tools.eclipse;
+import scala.tools.eclipse.classpath.ClasspathTests;
import scala.tools.eclipse.completion.CompletionTests;
import scala.tools.eclipse.hyperlinks.HyperlinkDetectorTests;
@@ -33,6 +34,7 @@
CompletionTests.class,
AbstractMethodVerifierTest.class,
SbtBuilderTest.class,
- PCTest.class
+ PCTest.class,
+ ClasspathTests.class
})
class TestsSuite { }
View
244 org.scala-ide.sdt.core.tests/src/scala/tools/eclipse/classpath/ClasspathTests.scala
@@ -0,0 +1,244 @@
+package scala.tools.eclipse.classpath
+
+import scala.tools.eclipse.testsetup.TestProjectSetup
+import org.junit.Assert._
+import org.junit.Test
+import org.eclipse.jdt.core.JavaCore
+import org.eclipse.core.resources.IResource
+import org.eclipse.core.resources.IncrementalProjectBuilder
+import org.eclipse.core.runtime.NullProgressMonitor
+import org.eclipse.core.runtime.Path
+import org.junit.Before
+import org.eclipse.jdt.core.IClasspathEntry
+import org.eclipse.core.resources.IMarker
+import scala.tools.eclipse.ScalaPlugin
+import org.junit.After
+import org.junit.Ignore
+
+object ClasspathTests extends TestProjectSetup("classpath")
+
+class ClasspathTests {
+
+ import ClasspathTests._
+
+ /**
+ * The default classpath, with the eclipse scala container.
+ */
+ val baseRawClasspath= project.javaProject.getRawClasspath()
+
+ /**
+ * The classpath, with the eclipse scala container removed.
+ */
+ def cleanRawClasspath= for (classpathEntry <- baseRawClasspath
+ if classpathEntry.getPath().toPortableString() != "org.scala-ide.sdt.launching.SCALA_CONTAINER")
+ yield classpathEntry
+
+ @After
+ def resetClasspath() {
+ setRawClasspathAndCheckMarkers(baseRawClasspath, 0, 0)
+ }
+
+ /**
+ * The scala library is defined as part of the eclipse container in the classpath (default case)
+ */
+ @Test
+ def eclipseContainerScalaLibrary() {
+ setRawClasspathAndCheckMarkers(baseRawClasspath, 0, 0)
+ }
+
+ /**
+ * No scala library defined in the classpath
+ */
+ @Test
+ def noScalaLibrary() {
+ setRawClasspathAndCheckMarkers(cleanRawClasspath, 0, 1)
+ }
+
+ /**
+ * Two scala library defined in the classpath, the eclipse container one, and one from the lib folder
+ */
+ @Test
+ def twoScalaLibraries() {
+ setRawClasspathAndCheckMarkers(baseRawClasspath :+ JavaCore.newLibraryEntry(new Path("/classpath/lib/2.10.x/scala-library.jar"), null, null), 0, 1)
+ }
+
+ /**
+ * Two scala library defined in the classpath, the eclipse container one, and one with a different name.
+ */
+ @Test
+ def twoScalaLibrariesWithDifferentName() {
+ setRawClasspathAndCheckMarkers(baseRawClasspath :+ JavaCore.newLibraryEntry(new Path("/classpath/lib/2.10.x/my-scala-library.jar"), null, null), 0, 1)
+ }
+
+ /**
+ * The scala library is defined using a classpath variable, with a different but compatible version
+ */
+ @Test
+ def usingClasspathVariable() {
+ // create a classpath variable
+ JavaCore.setClasspathVariable("CLASSPATH_TEST_LIB", new Path("/classpath/lib/" + ScalaPlugin.plugin.shortScalaVer + ".x/"), new NullProgressMonitor)
+ setRawClasspathAndCheckMarkers(cleanRawClasspath :+ JavaCore.newVariableEntry(new Path("CLASSPATH_TEST_LIB/scala-library.jar"), null, null), 1, 0)
+ }
+
+ /**
+ * The scala-library.jar from the lib folder is marked as being a different version, but compatible
+ */
+ @Test
+ def differentButCompatibleVersion() {
+ setRawClasspathAndCheckMarkers(cleanRawClasspath :+ JavaCore.newLibraryEntry(new Path("/classpath/lib/" + ScalaPlugin.plugin.shortScalaVer + ".x/scala-library.jar"), null, null), 1, 0)
+ }
+
+ /**
+ * The scala-library.jar is marked as being a different, incompatible version
+ */
+ @Test
+ def differentAndIncompatibleVersion() {
+ val newRawClasspath= cleanRawClasspath :+
+ JavaCore.newLibraryEntry(new Path("/classpath/lib/" +
+ (ScalaPlugin.plugin.shortScalaVer match {
+ case "2.8" => "2.9"
+ case "2.9" => "2.10"
+ case "2.10" => "2.8"
+ case _ =>
+ fail("Unsupported embedded scala library version " + ScalaPlugin.plugin.scalaVer +". Please update the test.")
+ ""
+ }) + ".x/scala-library.jar"), null, null)
+
+ setRawClasspathAndCheckMarkers(newRawClasspath, 0, 1)
+ }
+
+ /**
+ * The properties file in scala-library.jar doesn't contain the version information
+ */
+ @Test
+ def noVersionInPropertiesFile() {
+ setRawClasspathAndCheckMarkers(cleanRawClasspath :+ JavaCore.newLibraryEntry(new Path("/classpath/lib/noversion/scala-library.jar"), null, null), 0, 1)
+ }
+
+ /**
+ * The scala-library.jar doesn't contain a properties file.
+ */
+ @Test
+ def noPropertiesFile() {
+ setRawClasspathAndCheckMarkers(cleanRawClasspath :+ JavaCore.newLibraryEntry(new Path("/classpath/lib/noproperties/scala-library.jar"), null, null), 0, 1)
+ }
+
+ /**
+ * The library has a different name, but with a compatible version and contains scala.Predef
+ */
+ @Test
+ def differentNameWithCompatibleVersion() {
+ setRawClasspathAndCheckMarkers(cleanRawClasspath :+ JavaCore.newLibraryEntry(new Path("/classpath/lib/" + ScalaPlugin.plugin.shortScalaVer + ".x/my-scala-library.jar"), null, null), 1, 0)
+ }
+
+ /**
+ * The library has a different name, but with a compatible version and contains scala.Predef
+ */
+ @Test
+ def differentNameWithIncompatibleVersion() {
+ val newRawClasspath= cleanRawClasspath :+
+ JavaCore.newLibraryEntry(new Path("/classpath/lib/" +
+ (ScalaPlugin.plugin.shortScalaVer match {
+ case "2.8" => "2.9"
+ case "2.9" => "2.10"
+ case "2.10" => "2.8"
+ case _ =>
+ fail("Unsupported embedded scala library version " + ScalaPlugin.plugin.scalaVer +". Please update the test.")
+ ""
+ }) + ".x/my-scala-library.jar"), null, null)
+
+ setRawClasspathAndCheckMarkers(newRawClasspath, 0, 1)
+ }
+
+ /**
+ *
+ */
+
+ /**
+ * check that the error marker is kept even after a clean
+ */
+ @Test
+ def errorKeptAfterClean() {
+ setRawClasspathAndCheckMarkers(cleanRawClasspath, 0, 1)
+
+ project.underlying.build(IncrementalProjectBuilder.CLEAN_BUILD, new NullProgressMonitor)
+ project.underlying.build(IncrementalProjectBuilder.FULL_BUILD, new NullProgressMonitor)
+
+ checkMarkers(0, 1)
+ }
+
+ /**
+ * check the code is not compiled if the classpath is not right (no error reported in scala files)
+ */
+ @Test
+ def errorInClasspathStopBuild() {
+ project.underlying.build(IncrementalProjectBuilder.CLEAN_BUILD, new NullProgressMonitor)
+ project.underlying.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, new NullProgressMonitor)
+
+ // no error on the project itself
+ checkMarkers(0, 0)
+
+ // two excepted code errors
+ var markers= project.underlying.findMarkers("org.scala-ide.sdt.core.problem", false, IResource.DEPTH_INFINITE)
+ assertEquals("Unexpected number of scala problems in project", 2, markers.length)
+
+ // switch to an invalid classpath
+ setRawClasspathAndCheckMarkers(cleanRawClasspath, 0, 1)
+
+ project.underlying.build(IncrementalProjectBuilder.CLEAN_BUILD, new NullProgressMonitor)
+ project.underlying.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, new NullProgressMonitor)
+
+ // one error on the project
+ checkMarkers(0, 1)
+
+ // no additional code errors
+ markers= project.underlying.findMarkers("org.scala-ide.sdt.core.problem", false, IResource.DEPTH_INFINITE)
+ assertEquals("Unexpected number of scala problems in project", 1, markers.length)
+ }
+
+ /**
+ * Set the new classpath and check the number of errors and warnings attached to the project.
+ */
+ private def setRawClasspathAndCheckMarkers(newRawClasspath: Array[IClasspathEntry], expectedNbOfWarningMarker: Int, expectedNbOfErrorMarker: Int) {
+ project.javaProject.setRawClasspath(newRawClasspath, new NullProgressMonitor)
+ checkMarkers(expectedNbOfWarningMarker, expectedNbOfErrorMarker)
+ }
+
+ /**
+ * Check the number of errors and warnings attached to the project.
+ */
+ private def checkMarkers(expectedNbOfWarningMarker: Int, expectedNbOfErrorMarker: Int) {
+ val TIMEOUT= 5000
+
+ // check the classpathValid state
+ assertEquals("Unexpected classpath validity state", expectedNbOfErrorMarker == 0, project.isClasspathValid())
+
+ var nbOfWarningMarker= 0
+ var nbOfErrorMarker= 0
+
+ for (i <- 1 to (TIMEOUT / 200)) {
+ // count the markers on the project
+ nbOfWarningMarker= 0
+ nbOfErrorMarker= 0
+ for (marker <- project.underlying.findMarkers("org.scala-ide.sdt.core.problem", false, IResource.DEPTH_ZERO))
+ marker.getAttribute(IMarker.SEVERITY, 0) match {
+ case IMarker.SEVERITY_ERROR => nbOfErrorMarker+=1
+ case IMarker.SEVERITY_WARNING => nbOfWarningMarker+=1
+ case _ =>
+ }
+
+ if (nbOfWarningMarker == expectedNbOfWarningMarker && nbOfErrorMarker == expectedNbOfErrorMarker) {
+ // markers are fine, we're done
+ return
+ }
+
+ // wait a bit before trying again
+ Thread.sleep(200)
+ }
+
+ // after TIMEOUT, we didn't get the expected value
+ assertEquals("Unexpected nb of warning markers", expectedNbOfWarningMarker, nbOfWarningMarker)
+ assertEquals("Unexpected nb of error markers", expectedNbOfErrorMarker, nbOfErrorMarker)
+ }
+
+}
View
7 org.scala-ide.sdt.core.tests/test-workspace/classpath/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
View
18 org.scala-ide.sdt.core.tests/test-workspace/classpath/.project
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>classpath</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.scala-ide.sdt.core.scalabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.scala-ide.sdt.core.scalanature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.10.x/my-scala-library.jar
Binary file not shown
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.10.x/scala-library.jar
Binary file not shown
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.8.x/my-scala-library.jar
Binary file not shown
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.8.x/scala-library.jar
Binary file not shown
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.9.x/my-scala-library.jar
Binary file not shown
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/2.9.x/scala-library.jar
Binary file not shown
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/noproperties/scala-library.jar
Binary file not shown
View
BIN  org.scala-ide.sdt.core.tests/test-workspace/classpath/lib/noversion/scala-library.jar
Binary file not shown
View
12 org.scala-ide.sdt.core.tests/test-workspace/classpath/src/test/Test.scala
@@ -0,0 +1,12 @@
+package test
+
+class Test {
+
+ var x: ArrayList= null
+
+ def foo() {
+ var s= "s"
+ s= 2
+ }
+
+}
View
25 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaBuilder.scala
@@ -6,16 +6,18 @@
package scala.tools.eclipse
import scala.collection.mutable.HashSet
+
import java.{ lang => jl, util => ju }
+
import org.eclipse.core.resources.{ IFile, IncrementalProjectBuilder, IProject, IResource, IResourceDelta, IResourceDeltaVisitor, IResourceVisitor }
import org.eclipse.core.runtime.{ IProgressMonitor, IPath, SubMonitor }
import org.eclipse.jdt.internal.core.JavaModelManager
import org.eclipse.jdt.internal.core.builder.{ JavaBuilder, NameEnvironment, State }
+
import scala.tools.eclipse.javaelements.JDTUtils
import scala.tools.eclipse.util.{ FileUtils, ReflectionUtils }
-import util.HasLogger
-class ScalaBuilder extends IncrementalProjectBuilder with HasLogger {
+class ScalaBuilder extends IncrementalProjectBuilder {
def plugin = ScalaPlugin.plugin
private val scalaJavaBuilder = new GeneralScalaJavaBuilder
@@ -34,6 +36,12 @@ class ScalaBuilder extends IncrementalProjectBuilder with HasLogger {
override def build(kind : Int, ignored : ju.Map[_, _], monitor : IProgressMonitor) : Array[IProject] = {
import IncrementalProjectBuilder._
import buildmanager.sbtintegration.EclipseSbtBuildManager
+
+ // check the classpath
+ if (!plugin.getScalaProject(getProject).isClasspathValid()) {
+ // bail out is the classpath in not valid
+ return new Array[IProject](0)
+ }
val project = plugin.getScalaProject(getProject)
@@ -66,17 +74,8 @@ class ScalaBuilder extends IncrementalProjectBuilder with HasLogger {
// Only for sbt which is able to track external dependencies properly
project.buildManager match {
case _: EclipseSbtBuildManager =>
-
- def hasChanges(prj: IProject): Boolean = {
- val delta = getDelta(prj)
- delta == null || delta.getKind != IResourceDelta.NO_CHANGE
- }
-
- if (project.externalDepends.exists(hasChanges)) {
- // reset presentation compilers if a dependency has been rebuilt
- logger.debug("Resetting presentation compiler for %s due to dependent project change".format(project.underlying.getName()))
- project.resetPresentationCompiler
-
+ if (project.externalDepends.exists(
+ x => { val delta = getDelta(x); delta == null || delta.getKind != IResourceDelta.NO_CHANGE})) {
// in theory need to be able to identify the exact dependencies
// but this is deeply rooted inside the sbt dependency tracking mechanism
// so we just tell it to have a look at all the files
View
29 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaPlugin.scala
@@ -84,7 +84,7 @@ class ScalaPlugin extends AbstractUIPlugin with IResourceChangeListener with IEl
val javaFileExtn = ".java"
val jarFileExtn = ".jar"
- private def cutVersion(version: String): String = {
+ def cutVersion(version: String): String = {
val pattern = "(\\d)\\.(\\d+)\\..*".r
version match {
case pattern(major, minor)=>
@@ -135,12 +135,12 @@ class ScalaPlugin extends AbstractUIPlugin with IResourceChangeListener with IEl
if (!headlessMode) {
ResourcesPlugin.getWorkspace.addResourceChangeListener(this, IResourceChangeEvent.PRE_CLOSE)
- JavaCore.addElementChangedListener(this)
PlatformUI.getWorkbench.getEditorRegistry.setDefaultEditor("*.scala", editorId)
ScalaPlugin.getWorkbenchWindow map (_.getPartService().addPartListener(ScalaPlugin.this))
diagnostic.StartupDiagnostics.run
}
- logger.info("Scala compiler bundle: " + scalaCompilerBundle.getLocation)
+ JavaCore.addElementChangedListener(this)
+ println("Scala compiler bundle: " + scalaCompilerBundle.getLocation)
}
override def stop(context: BundleContext) = {
@@ -195,12 +195,29 @@ class ScalaPlugin extends AbstractUIPlugin with IResourceChangeListener with IEl
override def elementChanged(event: ElementChangedEvent) {
import scala.collection.mutable.ListBuffer
+ import IJavaElement._
+ import IJavaElementDelta._
+
+ // check if the changes are linked with the build path
+ val modelDelta= event.getDelta()
+ if (JAVA_MODEL == modelDelta.getElement().getElementType() && modelDelta.getKind() == CHANGED && (modelDelta.getFlags() & F_CHILDREN) != 0) {
+ val innerDelta= modelDelta.getAffectedChildren()(0)
+ if (innerDelta.getKind() == IJavaElementDelta.CHANGED && (innerDelta.getFlags() & IJavaElementDelta.F_RESOLVED_CLASSPATH_CHANGED) != 0) {
+ innerDelta.getElement() match {
+ case javaProject: IJavaProject => {
+ if (isScalaProject(javaProject)) {
+ getScalaProject(javaProject.getProject()).classpathHasChanged()
+ }
+ }
+ case _ =>
+ }
+ }
+ }
+
+ // process deleted files
val buff = new ListBuffer[ScalaSourceFile]
def findRemovedSources(delta: IJavaElementDelta) {
- import IJavaElement._
- import IJavaElementDelta._
-
val isChanged = delta.getKind == CHANGED
val isRemoved = delta.getKind == REMOVED
def hasFlag(flag: Int) = (delta.getFlags & flag) != 0
View
147 org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaProject.scala
@@ -26,9 +26,13 @@ import util.SWTUtils.asyncExec
import EclipseUtils.workspaceRunnableIn
import scala.tools.eclipse.properties.CompilerSettings
import scala.tools.eclipse.util.HasLogger
+import scala.collection.mutable.ListBuffer
+import scala.actors.Actor
+import org.eclipse.jdt.core.IJarEntryResource
+import java.util.Properties
+import org.eclipse.jdt.core.IPackageFragmentRoot
-
-trait BuildSuccessListener {
+trait BuildSuccessListener {
def buildSuccessful(): Unit
}
@@ -38,8 +42,10 @@ class ScalaProject(val underlying: IProject) extends HasLogger {
private var classpathUpdate: Long = IResource.NULL_STAMP
private var buildManager0: EclipseBuildManager = null
private var hasBeenBuilt = false
- private val resetPendingLock = new Object
- private var resetPending = false
+
+ private var classpathCheckLock= new Object
+ private var classpathHasBeenChecked= false
+ private var classpathValid= false;
private val buildListeners = new HashSet[BuildSuccessListener]
@@ -49,7 +55,6 @@ class ScalaProject(val underlying: IProject) extends HasLogger {
private val presentationCompiler = new Cached[Option[ScalaPresentationCompiler]] {
override def create() = {
- checkClasspathTimeStamp(shouldReset = false)
try {
val settings = new Settings
settings.printtypes.tryToSet(Nil)
@@ -341,22 +346,121 @@ class ScalaProject(val underlying: IProject) extends HasLogger {
}
}
- /** Check if the .classpath file has been changed since the last check.
- * If the saved timestamp does not match the file timestamp, reset the
- * two compilers.
+// /** Check if the .classpath file has been changed since the last check.
+// * If the saved timestamp does not match the file timestamp, reset the
+// * two compilers.
+// */
+// def checkClasspathTimeStamp(shouldReset: Boolean): Unit = plugin.check {
+// val cp = underlying.getFile(".classpath")
+// if (cp.exists)
+// classpathUpdate match {
+// case IResource.NULL_STAMP => classpathUpdate = cp.getModificationStamp()
+// case stamp if stamp == cp.getModificationStamp() =>
+// case _ =>
+// classpathUpdate = cp.getModificationStamp()
+// if (shouldReset) resetCompilers()
+// }
+// }
+
+ /**
+ * Manage the possible classpath error/warning reported on the project.
*/
- def checkClasspathTimeStamp(shouldReset: Boolean): Unit = plugin.check {
- val cp = underlying.getFile(".classpath")
- if (cp.exists)
- classpathUpdate match {
- case IResource.NULL_STAMP => classpathUpdate = cp.getModificationStamp()
- case stamp if stamp == cp.getModificationStamp() =>
- case _ =>
- classpathUpdate = cp.getModificationStamp()
- if (shouldReset) resetCompilers()
+ private def setClasspathError(severity: Int, message: String) {
+ // set the state
+ classpathValid= severity != IMarker.SEVERITY_ERROR
+ classpathHasBeenChecked= true
+ new Thread() {
+ override def run() {
+ // clean the markers
+ underlying.deleteMarkers(plugin.problemMarkerId, false, IResource.DEPTH_ZERO)
+
+ // add a new marker if needed
+ severity match {
+ case IMarker.SEVERITY_ERROR | IMarker.SEVERITY_WARNING =>
+ val marker= underlying.createMarker(plugin.problemMarkerId)
+ marker.setAttribute(IMarker.MESSAGE, message)
+ marker.setAttribute(IMarker.SEVERITY, severity)
+ case _ =>
+ }
+
}
+ }.start()
}
-
+
+ /**
+ * Return <code>true</code> if the classpath is deemed valid.
+ * Check the classpath if it has not been checked yet.
+ */
+ def isClasspathValid(): Boolean = {
+ classpathCheckLock.synchronized {
+ if (!classpathHasBeenChecked)
+ checkClasspath()
+ classpathValid
+ }
+ }
+
+ /**
+ * Check if the classpath is valid for scala.
+ * It is said valid if it contains one and only scala library jar, with a version compatible
+ * with the one from the scala-ide plug-in
+ */
+ def classpathHasChanged() {
+ classpathCheckLock.synchronized {
+ try {
+ resetCompilers()
+ // mark as in progress
+ classpathHasBeenChecked= false
+ checkClasspath()
+ }
+ }
+ }
+
+ private def checkClasspath() {
+ // look for all package fragment roots containing instances of scala.Predef
+ val fragmentRoots= new ListBuffer[IPackageFragmentRoot]
+ for (fragmentRoot <- javaProject.getAllPackageFragmentRoots()) {
+ val fragment= fragmentRoot.getPackageFragment("scala")
+ fragmentRoot.getKind() match {
+ case IPackageFragmentRoot.K_BINARY =>
+ if (fragment.getClassFile("Predef.class").exists())
+ fragmentRoots+= fragmentRoot
+ case _ => // look only in jars. SBT doesn't start without one, and refined is not really happy either
+ }
+ }
+
+ // check the found package fragment roots
+ fragmentRoots.length match {
+ case 0 => // unable to find any trace of scala library
+ setClasspathError(IMarker.SEVERITY_ERROR, "Unable to find a scala library. Please add the scala container or a scala library jar to the build path.")
+ case 1 => // one and only one, now check if the version number is contained in library.properties
+ for (resource <- fragmentRoots(0).getNonJavaResources())
+ resource match {
+ case jarEntry: IJarEntryResource if jarEntry.isFile() && "library.properties".equals(jarEntry.getName) =>
+ val properties= new Properties()
+ properties.load(jarEntry.getContents())
+ val version= properties.getProperty("version.number")
+ if (version != null && version == plugin.scalaVer) {
+ // exactly the same version, should be from the container. Perfect
+ setClasspathError(0, null)
+ } else {
+ if (version != null && plugin.cutVersion(version) == plugin.shortScalaVer) {
+ // compatible version. Still, add warning message
+ setClasspathError(IMarker.SEVERITY_WARNING, "The version of scala library found in the build path is different from the one provided by scala IDE: " + version + ". Expected: " + plugin.scalaVer + ". Make sure you know what you are doing.")
+ } else {
+ // incompatible version
+ setClasspathError(IMarker.SEVERITY_ERROR, "The version of scala library found in the build path is incompatible with the one provided by scala IDE: " + version + ". Expected: " + plugin.scalaVer + ". Please replace the scala library with the scala container or a compatible scala library jar.")
+ }
+ }
+ return
+ case _ =>
+ }
+ // no library.properties, not good
+ setClasspathError(IMarker.SEVERITY_ERROR, "The scala library found in the build path doesn't contain a library.properties file. Please replace the scala library with the scala container or a valid scala library jar")
+ case _ => // 2 or more of them, not good
+ setClasspathError(IMarker.SEVERITY_ERROR, "More than one scala library found in the build path. Please update the project build path so it contains only one scala library reference")
+ }
+ }
+
private def refreshOutput: Unit = {
val res = plugin.workspaceRoot.findMember(javaProject.getOutputLocation)
if (res ne null)
@@ -388,7 +492,7 @@ class ScalaProject(val underlying: IProject) extends HasLogger {
setting <- box.userSettings; if filter(setting)
) {
val value0 = store.getString(SettingConverterUtil.convertNameToProperty(setting.name))
-// logger.info("[%s] initializing %s to %s".format(underlying.getName(), setting.name, value0.toString))
+ logger.info("[%s] initializing %s to %s".format(underlying.getName(), setting.name, value0.toString))
try {
val value = if (setting ne settings.pluginsDir) value0 else {
ScalaPlugin.plugin.continuationsClasses map {
@@ -479,7 +583,6 @@ class ScalaProject(val underlying: IProject) extends HasLogger {
}
def buildManager = {
- checkClasspathTimeStamp(shouldReset = true)
if (buildManager0 == null) {
val settings = new Settings
initialize(settings, _ => true)
@@ -539,6 +642,10 @@ class ScalaProject(val underlying: IProject) extends HasLogger {
def clean(implicit monitor: IProgressMonitor) = {
underlying.deleteMarkers(plugin.problemMarkerId, true, IResource.DEPTH_INFINITE)
+ // mark the classpath as not checked
+ classpathCheckLock.synchronized {
+ classpathHasBeenChecked= false
+ }
resetCompilers
if (buildManager0 != null)
buildManager0.clean(monitor)
Please sign in to comment.
Something went wrong with that request. Please try again.