Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Truncate too long build error messages displayed in resources' marker

Markers are a general mechanism for associating notes and meta-data with
resources.  The Eclipse environments dictates that the text message passed to a
marker should not be bigger than 21000 chars, or an assertion failure saying

> Marker property value is too long

is thrown on the user's face.

The actual logic for resizing the build error problem passed to a marker
already existed in two places. While the message passed to the created marker
was correctly truncated in ``FileUtils.buildError``, it was not in
``ScalaProject.buildErrors``.

As part of this commit, I've centralized the creation of resource markers in
``MarkerFactory``, and build problem markers are now created using
``BuildProblemMarker`` (it's a subclass of ``MarkerFactory```).

More cleaning up could be done so that all markers are created only through
sublcasses of `MarkerFactory``. Though, such a big refactoring seem too risky
at the moment, as this commit will be merged in ``release/2.0.x`` branch.

Fix #1001107
(cherry picked from commit be013c2)

Conflicts:

	org.scala-ide.sdt.core/src/scala/tools/eclipse/buildmanager/BuildReporter.scala
	org.scala-ide.sdt.core/src/scala/tools/eclipse/buildmanager/refined/EclipseRefinedBuildManager.scala
	org.scala-ide.sdt.core/src/scala/tools/eclipse/buildmanager/sbtintegration/EclipseSbtBuildManager.scala
  • Loading branch information...
commit 81d097217bd47e70ca398ea376578b3fce52088a 1 parent b317578
Mirco Dotta authored July 04, 2012
1  org.scala-ide.sdt.core/META-INF/MANIFEST.MF
@@ -82,6 +82,7 @@ Export-Package:
82 82
  scala.tools.eclipse.markoccurrences,
83 83
  scala.tools.eclipse.properties,
84 84
  scala.tools.eclipse.quickfix,
  85
+ scala.tools.eclipse.resources,
85 86
  scala.tools.eclipse.refactoring,
86 87
  scala.tools.eclipse.refactoring.rename,
87 88
  scala.tools.eclipse.refactoring.ui,
15  org.scala-ide.sdt.core/src/scala/tools/eclipse/ScalaProject.scala
@@ -144,21 +144,6 @@ class ScalaProject private (val underlying: IProject) extends HasLogger {
144 144
   /** Does this project have the Scala nature? */
145 145
   def hasScalaNature = 
146 146
     ScalaPlugin.plugin.isScalaProject(underlying)
147  
-
148  
-  /** Generic build error, without a source position. It creates a marker in the
149  
-   *  Problem views.
150  
-   */
151  
-  def buildError(severity: Int, msg: String, monitor: IProgressMonitor) =
152  
-    workspaceRunnableIn(underlying.getWorkspace, monitor) { m =>
153  
-      val mrk = underlying.createMarker(plugin.problemMarkerId)
154  
-      mrk.setAttribute(IMarker.SEVERITY, severity)
155  
-      val string = msg.map {
156  
-        case '\n' => ' '
157  
-        case '\r' => ' '
158  
-        case c    => c
159  
-      }.mkString("", "", "")
160  
-      mrk.setAttribute(IMarker.MESSAGE, string)
161  
-    }
162 147
   
163 148
   def settingsError(severity: Int, msg: String, monitor: IProgressMonitor) =
164 149
     workspaceRunnableIn(underlying.getWorkspace, monitor) { m =>
18  org.scala-ide.sdt.core/src/scala/tools/eclipse/buildmanager/BuildProblemMarker.scala
... ...
@@ -0,0 +1,18 @@
  1
+package scala.tools.eclipse.buildmanager
  2
+
  3
+import org.eclipse.core.resources.IResource
  4
+import org.eclipse.core.resources.IMarker
  5
+import scala.tools.eclipse.resources.MarkerFactory
  6
+import scala.tools.eclipse.ScalaPlugin
  7
+import scala.tools.eclipse.ScalaProject
  8
+
  9
+/** Factory for creating markers used to report build problems (i.e., compilation errors). */
  10
+object BuildProblemMarker extends MarkerFactory(ScalaPlugin.plugin.problemMarkerId) {
  11
+  /** Create a marker indicating an error state for the passed Scala `project`. */
  12
+  def create(project: ScalaProject, e: Throwable): Unit =
  13
+    create(project.underlying, "Error in Scala compiler: " + e.getMessage)
  14
+
  15
+  /** Create a marker indicating an error state for the passed `resource`. */
  16
+  def create(resource: IResource, msg: String): Unit =
  17
+    create(resource, IMarker.SEVERITY_ERROR, msg)
  18
+}
14  org.scala-ide.sdt.core/src/scala/tools/eclipse/buildmanager/BuildReporter.scala
... ...
@@ -1,14 +1,12 @@
1 1
 package scala.tools.eclipse.buildmanager
2 2
 
3 3
 import scala.tools.eclipse.{EclipseBuildManager, TaskScanner, ScalaProject}
4  
-
  4
+import scala.tools.eclipse.resources.MarkerFactory
5 5
 import scala.tools.nsc.Settings
6 6
 import scala.tools.nsc.reporters.Reporter
7 7
 import scala.tools.nsc.util.{ Position, NoPosition }
8 8
 import scala.tools.eclipse.util.{ EclipseResource, FileUtils, HasLogger }
9  
-
10 9
 import scala.collection.mutable.ListBuffer
11  
-
12 10
 import org.eclipse.core.resources.{ IFile, IMarker }
13 11
 import org.eclipse.core.runtime.IProgressMonitor
14 12
 
@@ -40,7 +38,7 @@ abstract class BuildReporter(private[buildmanager] val project0: ScalaProject, s
40 38
 	        source.file match {
41 39
 	          case EclipseResource(i : IFile) => 
42 40
 	            if (!pos.source.file.hasExtension("java")) {
43  
-	              FileUtils.buildError(i, eclipseSeverity, msg, pos.point, length, pos.line, null)
  41
+	              BuildProblemMarker.create(i, eclipseSeverity, msg, MarkerFactory.Position(pos.point, length, pos.line))
44 42
 	              prob += new BuildProblem(severity, msg, pos)
45 43
 	            } else
46 44
 	              logger.info("suppressed error in Java file: %s".format(msg))
@@ -52,11 +50,11 @@ abstract class BuildReporter(private[buildmanager] val project0: ScalaProject, s
52 50
 	                // for instance, when a source file (on the sourcepath) is newer than the classfile
53 51
 	                // the compiler will create PlainFile instances in that case
54 52
 	                prob += new BuildProblem(severity, msg, pos)
55  
-	                FileUtils.buildError(i, eclipseSeverity, msg, pos.point, length, pos.line, null)
  53
+	                BuildProblemMarker.create(i, eclipseSeverity, msg, MarkerFactory.Position(pos.point, length, pos.line))
56 54
 	              case _ =>
57 55
 	                logger.info("no EclipseResource associated to %s [%s]".format(f.path, f.getClass))
58 56
 	                prob += new BuildProblem(severity, msg, NoPosition)
59  
-	                project0.buildError(eclipseSeverity, msg, null)
  57
+	                BuildProblemMarker.create(project0.underlying, eclipseSeverity, msg)
60 58
 	            }
61 59
 	        }
62 60
 	      }
@@ -67,12 +65,12 @@ abstract class BuildReporter(private[buildmanager] val project0: ScalaProject, s
67 65
 		      	  logger.info("[Buildmanager info] " + msg)
68 66
 	          case _ =>
69 67
 		      	  prob += new BuildProblem(severity, msg, NoPosition)
70  
-		      	  project0.buildError(eclipseSeverity, msg, null)
  68
+		      	  BuildProblemMarker.create(project0.underlying, eclipseSeverity, msg)
71 69
 	        }
72 70
 	    } catch {
73 71
 	      case ex : UnsupportedOperationException => 
74 72
 	        prob += new BuildProblem(severity, msg, NoPosition)
75  
-	        project0.buildError(eclipseSeverity, msg, null)
  73
+	        BuildProblemMarker.create(project0.underlying, eclipseSeverity, msg)
76 74
 	    }
77 75
     }
78 76
   }
2  org.scala-ide.sdt.core/src/scala/tools/eclipse/buildmanager/refined/EclipseRefinedBuildManager.scala
@@ -81,7 +81,7 @@ class EclipseRefinedBuildManager(project: ScalaProject, settings0: Settings)
81 81
     } catch {
82 82
       case e =>
83 83
         hasErrors = true
84  
-        project.buildError(IMarker.SEVERITY_ERROR, "Error in Scala compiler: " + e.getMessage, null)
  84
+        BuildProblemMarker.create(project, e)
85 85
         logger.error("Error in Scala compiler", e)
86 86
     }
87 87
     if (!hasErrors)
12  org.scala-ide.sdt.core/src/scala/tools/eclipse/buildmanager/sbtintegration/EclipseSbtBuildManager.scala
@@ -343,7 +343,7 @@ class EclipseSbtBuildManager(val project: ScalaProject, settings0: Settings)
343 343
   	      logger.info("Cannot find Scala library on the classpath. Verify your build path! Using default library corresponding to the compiler")
344 344
   	      //ScalaPlugin.plugin.sbtScalaLib.get.toFile
345 345
   	      val e = new Exception("Cannot find Scala library on the classpath. Verify your build path!")
346  
-  	      project.buildError(IMarker.SEVERITY_ERROR, e.getMessage(), null)
  346
+  	      BuildProblemMarker.create(project.underlying, e.getMessage)
347 347
           logger.error("Error in Scala SBT builder", e)
348 348
   	      return
349 349
   	  }
@@ -361,13 +361,13 @@ class EclipseSbtBuildManager(val project: ScalaProject, settings0: Settings)
361 361
       
362 362
       val analysisComp = new AnalysisCompile(conf, this, new SbtProgress())
363 363
 
364  
-    val extraAnalysis = upstreamAnalysis(project)
  364
+      val extraAnalysis = upstreamAnalysis(project)
365 365
 
366  
-    logger.debug("Retrieved the following upstream analysis: " + extraAnalysis)
  366
+      logger.debug("Retrieved the following upstream analysis: " + extraAnalysis)
367 367
 
368 368
   	  val order = project.storage.getString(SettingConverterUtil.convertNameToProperty(properties.ScalaPluginSettings.compileOrder.name))
369  
-    analysisComp.doCompile(
370  
-      scalac, javac, sources, reporter, settings0, CompileOrderMapper(order), analysisMap = extraAnalysis)
  369
+      analysisComp.doCompile(
  370
+        scalac, javac, sources, reporter, settings0, CompileOrderMapper(order), analysisMap = extraAnalysis)
371 371
   }
372 372
 
373 373
   /** Return the Analysis for all the dependencies that are Scala projects, and that 
@@ -434,7 +434,7 @@ class EclipseSbtBuildManager(val project: ScalaProject, settings0: Settings)
434 434
     } catch {
435 435
       case e =>
436 436
         hasErrors = true
437  
-        project.buildError(IMarker.SEVERITY_ERROR, "Error in Scala compiler: " + e.getMessage, null)
  437
+        BuildProblemMarker.create(project, e)
438 438
         logger.error("Error in Scala compiler", e)
439 439
     }
440 440
     
80  org.scala-ide.sdt.core/src/scala/tools/eclipse/resources/MarkerFactory.scala
... ...
@@ -0,0 +1,80 @@
  1
+package scala.tools.eclipse.resources
  2
+
  3
+import scala.tools.eclipse.util.EclipseUtils.workspaceRunnableIn
  4
+
  5
+import org.eclipse.core.resources.IMarker
  6
+import org.eclipse.core.resources.IResource
  7
+import org.eclipse.core.runtime.IProgressMonitor
  8
+
  9
+object MarkerFactory {
  10
+  case class Position(offset: Int, length: Int, line: Int)
  11
+}
  12
+
  13
+/** Generic factory for creating resource's markers.
  14
+  *
  15
+  * Markers are a general mechanism for associating notes and meta-data with resources.
  16
+  *
  17
+  * @param markerType A unique identifier for the created marker. Mind that a marker `X` can be a subtype of a marker `Y`.
  18
+  *                   See [[org.eclipse.core.resources.IMarker]] for more information.
  19
+  *
  20
+  * Example:
  21
+  *
  22
+  * {{{ class BuildProblemMarker extends MarkerFactory("org.scala-ide.sdt.core.problem") }}}
  23
+  */
  24
+abstract class MarkerFactory(markerType: String) {
  25
+  /** Create marker without a source position in the Problem view.
  26
+    * @param resource The resource to use to create the marker (hence, the marker will be associated to the passed resource)
  27
+    * @param severity Indicates the marker's error state. Its value can be one of:
  28
+    *                  [IMarker.SEVERITY_ERROR, IMarker.SEVERITY_WARNING, IMarker.SEVERITY_INFO]
  29
+    * @param msg      The text message displayed by the marker. Note, the passed message is truncated to 21000 chars.
  30
+    */
  31
+  def create(resource: IResource, severity: Int, msg: String): Unit = 
  32
+    createMarkerInWorkspaceAndApply(resource) { marker =>
  33
+      update(marker, severity, msg)
  34
+    }
  35
+
  36
+  /** Create marker with a source position in the Problem view.
  37
+    * @param resource The resource to use to create the marker (hence, the marker will be associated to the passed resource)
  38
+    * @param severity Indicates the marker's error state. Its value can be one of:
  39
+    *                 [IMarker.SEVERITY_ERROR, IMarker.SEVERITY_WARNING, IMarker.SEVERITY_INFO]
  40
+    * @param msg      The text message displayed by the marker. Note, the passed message is truncated to 21000 chars.
  41
+    * @param pos      The source position for the marker.
  42
+    */
  43
+  def create(resource: IResource, severity: Int, msg: String, pos: MarkerFactory.Position): Unit = 
  44
+    createMarkerInWorkspaceAndApply(resource) { marker =>
  45
+      update(marker, severity, msg)
  46
+      setPos(marker, pos)
  47
+    }
  48
+
  49
+  private def update(marker: IMarker, severity: Int, msg: String): IMarker = {
  50
+    marker.setAttribute(IMarker.SEVERITY, severity)
  51
+    // Marker attribute values are limited to <= 65535 bytes and setAttribute will assert if they
  52
+    // exceed this. To guard against this we trim to <= 21000 characters ... see
  53
+    // org.eclipse.core.internal.resources.MarkerInfo.checkValidAttribute for justification
  54
+    // of this arbitrary looking number
  55
+    val maxMarkerLen = 21000
  56
+    val trimmedMsg = msg.take(maxMarkerLen)
  57
+
  58
+    val attrValue = trimmedMsg.map {
  59
+      case '\n' | '\r' => ' '
  60
+      case c => c
  61
+    }
  62
+
  63
+    marker.setAttribute(IMarker.MESSAGE, attrValue)
  64
+    marker
  65
+  }
  66
+
  67
+  private def setPos(marker: IMarker, position: MarkerFactory.Position): IMarker = {
  68
+    if (position.offset != -1) {
  69
+      marker.setAttribute(IMarker.CHAR_START, position.offset)
  70
+      marker.setAttribute(IMarker.CHAR_END, position.offset + math.max(position.length, 1))
  71
+      marker.setAttribute(IMarker.LINE_NUMBER, position.line)
  72
+    }
  73
+    marker
  74
+  }
  75
+  
  76
+  private def createMarkerInWorkspaceAndApply(resource: IResource)(f: IMarker => Unit): Unit = workspaceRunnableIn(resource.getWorkspace) { _ => 
  77
+    val marker = resource.createMarker(markerType)
  78
+    f(marker)
  79
+  }
  80
+}
26  org.scala-ide.sdt.core/src/scala/tools/eclipse/util/FileUtils.scala
@@ -72,32 +72,6 @@ object FileUtils {
72 72
 
73 73
   def hasBuildErrors(file : IResource) : Boolean =
74 74
     file.findMarkers(plugin.problemMarkerId, true, IResource.DEPTH_INFINITE).exists(_.getAttribute(IMarker.SEVERITY) == IMarker.SEVERITY_ERROR)
75  
-  
76  
-  def buildError(file : IFile, severity : Int, msg : String, offset : Int, length : Int, line : Int, monitor : IProgressMonitor) =
77  
-    workspaceRunnableIn(file.getWorkspace, monitor) { m =>
78  
-      val mrk = file.createMarker(plugin.problemMarkerId)
79  
-      mrk.setAttribute(IMarker.SEVERITY, severity)
80  
-      
81  
-      // Marker attribute values are limited to <= 65535 bytes and setAttribute will assert if they
82  
-      // exceed this. To guard against this we trim to <= 21000 characters ... see
83  
-      // org.eclipse.core.internal.resources.MarkerInfo.checkValidAttribute for justification
84  
-      // of this arbitrary looking number
85  
-      val maxMarkerLen = 21000
86  
-      val trimmedMsg = msg.take(maxMarkerLen)
87  
-      
88  
-      val attrValue = trimmedMsg.map {
89  
-        case '\n' | '\r' => ' '
90  
-        case c => c
91  
-      }
92  
-      
93  
-      mrk.setAttribute(IMarker.MESSAGE , attrValue)
94  
-
95  
-      if (offset != -1) {
96  
-        mrk.setAttribute(IMarker.CHAR_START, offset)
97  
-        mrk.setAttribute(IMarker.CHAR_END, offset + math.max(length, 1))
98  
-        mrk.setAttribute(IMarker.LINE_NUMBER, line)
99  
-      }
100  
-    }
101 75
 
102 76
   def task(file: IFile, tag: String, msg: String, priority: String, offset: Int, length: Int, line: Int, monitor: IProgressMonitor) =
103 77
     workspaceRunnableIn(file.getWorkspace, monitor) { m =>

0 notes on commit 81d0972

Please sign in to comment.
Something went wrong with that request. Please try again.