Merge pull request #7251 from eed3si9n/wip/problem

Add concrete impl for Action
This commit is contained in:
eugene yokota 2023-05-14 14:30:24 -04:00 committed by GitHub
commit f539e12645
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 420 additions and 6 deletions

View File

@ -369,7 +369,7 @@ lazy val utilLogging = (project in file("internal") / "util-logging")
.enablePlugins(ContrabandPlugin, JsonCodecPlugin)
.dependsOn(utilInterface, collectionProj, coreMacrosProj)
.settings(
utilCommonSettings,
testedBaseSettings,
name := "Util Logging",
libraryDependencies ++=
Seq(
@ -383,7 +383,6 @@ lazy val utilLogging = (project in file("internal") / "util-logging")
sjsonNewScalaJson.value,
scalaReflect.value
),
libraryDependencies ++= Seq(scalacheck % "test", scalatest % "test"),
Compile / scalacOptions ++= (scalaVersion.value match {
case v if v.startsWith("2.12.") => List("-Ywarn-unused:-locals,-explicits,-privates")
case _ => List()
@ -397,6 +396,7 @@ lazy val utilLogging = (project in file("internal") / "util-logging")
if (name == "Throwable") Nil
else old(tpe)
},
Test / fork := true,
utilMimaSettings,
mimaBinaryIssueFilters ++= Seq(
exclude[DirectMissingMethodProblem]("sbt.internal.util.SuccessEvent.copy*"),

View File

@ -11,6 +11,8 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
// Note: Update InterfaceUtil.scala as well.
public interface Problem {
String category();

View File

@ -12,7 +12,17 @@ import java.util.Optional
import java.util.function.Supplier
import java.{ util => ju }
import xsbti.{ DiagnosticCode, DiagnosticRelatedInformation, Position, Problem, Severity, T2 }
import xsbti.{
Action,
DiagnosticCode,
DiagnosticRelatedInformation,
Position,
Problem,
Severity,
TextEdit,
WorkspaceEdit,
T2,
}
import scala.collection.mutable.ListBuffer
@ -130,6 +140,7 @@ object InterfaceUtil {
): Problem =
problem(cat, pos, msg, sev, rendered, None, List.empty[DiagnosticRelatedInformation])
@deprecated("Use the overload of this method with more arguments", "1.9.0")
def problem(
cat: String,
pos: Position,
@ -139,7 +150,59 @@ object InterfaceUtil {
diagnosticCode: Option[DiagnosticCode],
diagnosticRelatedInforamation: List[DiagnosticRelatedInformation]
): Problem =
new ConcreteProblem(cat, pos, msg, sev, rendered, diagnosticCode, diagnosticRelatedInforamation)
problem(
cat,
pos,
msg,
sev,
rendered,
diagnosticCode,
diagnosticRelatedInforamation,
List.empty[Action],
)
def problem(
cat: String,
pos: Position,
msg: String,
sev: Severity,
rendered: Option[String],
diagnosticCode: Option[DiagnosticCode],
diagnosticRelatedInformation: List[DiagnosticRelatedInformation],
actions: List[Action],
): Problem =
new ConcreteProblem(
cat,
pos,
msg,
sev,
rendered,
diagnosticCode,
diagnosticRelatedInformation,
actions,
)
def action(
title: String,
description: Option[String],
edit: WorkspaceEdit,
): Action =
new ConcreteAction(title, description, edit)
def workspaceEdit(changes: List[TextEdit]): WorkspaceEdit =
new ConcreteWorkspaceEdit(changes)
def textEdit(position: Position, newText: String): TextEdit =
new ConcreteTextEdit(position, newText)
def diagnosticCode(code: String, explanation: Option[String]): DiagnosticCode =
new ConcreteDiagnosticCode(code, explanation)
def diagnosticRelatedInformation(
position: Position,
message: String
): DiagnosticRelatedInformation =
new ConcreteDiagnosticRelatedInformation(position, message)
private final class ConcreteT2[A1, A2](a1: A1, a2: A2) extends T2[A1, A2] {
val get1: A1 = a1
@ -187,6 +250,42 @@ object InterfaceUtil {
override val startColumn = o2jo(startColumn0)
override val endLine = o2jo(endLine0)
override val endColumn = o2jo(endColumn0)
override def toString: String = {
val src = sourcePath0 match {
case Some(x) => s"$x"
case None => "none"
}
val line = line0 match {
case Some(x) => s":$x"
case None => ""
}
val offset = offset0 match {
case Some(x) => s":$x"
case None => ""
}
s"""$src$line$offset"""
}
private def toTuple(p: Position) =
(
p.line,
p.lineContent,
p.offset,
p.pointer,
p.pointerSpace,
p.sourcePath,
p.sourceFile,
p.startOffset,
p.endOffset,
p.startLine,
p.startColumn,
p.endLine,
p.endColumn,
)
override def hashCode: Int = toTuple(this).##
override def equals(o: Any): Boolean = o match {
case o: Position => toTuple(this) == toTuple(o)
case _ => false
}
}
private final class ConcreteProblem(
@ -196,7 +295,8 @@ object InterfaceUtil {
sev: Severity,
rendered0: Option[String],
diagnosticCode0: Option[DiagnosticCode],
diagnosticRelatedInformation0: List[DiagnosticRelatedInformation]
diagnosticRelatedInformation0: List[DiagnosticRelatedInformation],
actions0: List[Action],
) extends Problem {
val category = cat
val position = pos
@ -204,8 +304,116 @@ object InterfaceUtil {
val severity = sev
override val rendered = o2jo(rendered0)
override def diagnosticCode: Optional[DiagnosticCode] = o2jo(diagnosticCode0)
override def diagnosticRelatedInforamation(): ju.List[DiagnosticRelatedInformation] =
override def diagnosticRelatedInformation(): ju.List[DiagnosticRelatedInformation] =
l2jl(diagnosticRelatedInformation0)
@deprecated("use diagnosticRelatedInformation", "1.9.0")
override def diagnosticRelatedInforamation(): ju.List[DiagnosticRelatedInformation] =
diagnosticRelatedInformation()
override def actions(): ju.List[Action] =
l2jl(actions0)
override def toString = s"[$severity] $pos: $message"
private def toTuple(p: Problem) =
(
p.category,
p.position,
p.message,
p.severity,
p.rendered,
p.diagnosticCode,
p.diagnosticRelatedInformation,
p.actions,
)
override def hashCode: Int = toTuple(this).##
override def equals(o: Any): Boolean = o match {
case o: Problem => toTuple(this) == toTuple(o)
case _ => false
}
}
private final class ConcreteAction(
title0: String,
description0: Option[String],
edit0: WorkspaceEdit,
) extends Action {
val title: String = title0
val edit: WorkspaceEdit = edit0
override def description(): Optional[String] =
o2jo(description0)
override def toString(): String =
s"Action($title0, $description0, $edit0)"
private def toTuple(a: Action) =
(
a.title,
a.description,
a.edit,
)
override def hashCode: Int = toTuple(this).##
override def equals(o: Any): Boolean = o match {
case o: Action => toTuple(this) == toTuple(o)
case _ => false
}
}
private final class ConcreteWorkspaceEdit(changes0: List[TextEdit]) extends WorkspaceEdit {
override def changes(): ju.List[TextEdit] = l2jl(changes0)
override def toString(): String =
s"WorkspaceEdit($changes0)"
private def toTuple(w: WorkspaceEdit) = jl2l(w.changes)
override def hashCode: Int = toTuple(this).##
override def equals(o: Any): Boolean = o match {
case o: WorkspaceEdit => toTuple(this) == toTuple(o)
case _ => false
}
}
private final class ConcreteTextEdit(position0: Position, newText0: String) extends TextEdit {
val position: Position = position0
val newText: String = newText0
override def toString(): String =
s"TextEdit($position, $newText)"
private def toTuple(edit: TextEdit) =
(
edit.position,
edit.newText,
)
override def hashCode: Int = toTuple(this).##
override def equals(o: Any): Boolean = o match {
case o: TextEdit => toTuple(this) == toTuple(o)
case _ => false
}
}
private final class ConcreteDiagnosticCode(code0: String, explanation0: Option[String])
extends DiagnosticCode {
val code: String = code0
val explanation: Optional[String] = o2jo(explanation0)
override def toString(): String = s"DiagnosticCode($code)"
private def toTuple(c: DiagnosticCode) =
(
c.code,
c.explanation,
)
override def hashCode: Int = toTuple(this).##
override def equals(o: Any): Boolean = o match {
case o: DiagnosticCode => toTuple(this) == toTuple(o)
case _ => false
}
}
private final class ConcreteDiagnosticRelatedInformation(position0: Position, message0: String)
extends DiagnosticRelatedInformation {
val position: Position = position0
val message: String = message0
override def toString(): String = s"DiagnosticRelatedInformation($position, $message)"
private def toTuple(info: DiagnosticRelatedInformation) =
(
info.position,
info.message,
)
override def hashCode: Int = toTuple(this).##
override def equals(o: Any): Boolean = o match {
case o: DiagnosticRelatedInformation => toTuple(this) == toTuple(o)
case _ => false
}
}
}

View File

@ -0,0 +1,204 @@
/*
* sbt
* Copyright 2011 - 2018, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt
import java.net.URI
import hedgehog._
import hedgehog.runner._
import _root_.sbt.util.InterfaceUtil
import InterfaceUtil.{ jl2l, jo2o, l2jl }
import xsbti._
object ProblemTest extends Properties {
override def tests: List[Test] = List(
property(
"All problems can toString",
genProblem.forAll.map(toStringCheck),
),
property(
"All problems can be compared structurally",
genProblem.forAll.map(equalityCheck),
),
property(
"All diagnostic codes can be compared structurally",
genDiagnosticCode.forAll.map(equalityCheck),
),
property(
"All diagnostic related information can be compared structurally",
genDiagnosticRelatedInformation.forAll.map(equalityCheck),
),
property(
"All actions can be compared structurally",
genAction.forAll.map(equalityCheck),
),
)
def toStringCheck(p: Problem): Result =
Result.assert(p.toString() != "")
def equalityCheck(p: Problem): Result = {
val other = InterfaceUtil.problem(
p.category,
p.position,
p.message,
p.severity,
jo2o(p.rendered),
jo2o(p.diagnosticCode).map(copy),
jl2l(p.diagnosticRelatedInformation).map(copy),
jl2l(p.actions).map(copy),
)
Result
.assert(p == other)
.log(s"$p == $other")
}
def equalityCheck(c: DiagnosticCode): Result = {
val other = copy(c)
Result.assert(c == other)
}
def equalityCheck(info: DiagnosticRelatedInformation): Result = {
val other = copy(info)
Result.assert(info == other)
}
def equalityCheck(a: Action): Result = {
val other = copy(a)
Result.assert(a == other)
}
lazy val genProblem: Gen[Problem] =
for {
cat <- genString
pos <- genPosition
msg <- genString
sev <- genSeverity
rendered <- optString
code <- optDiagnosticCode
info <- listDiagnosticRelatedInformation
actions <- listAction
} yield InterfaceUtil.problem(
cat,
pos,
msg,
sev,
rendered,
code,
info,
actions,
)
lazy val optDiagnosticCode: Gen[Option[DiagnosticCode]] =
Gen.choice1(genDiagnosticCode.map(Some(_)), Gen.constant(None))
lazy val genDiagnosticCode: Gen[DiagnosticCode] =
for {
code <- Gen.int(Range.linear(0, 1024))
} yield InterfaceUtil.diagnosticCode("E" + code.toString, None)
lazy val genSeverity: Gen[Severity] =
Gen.element(Severity.Info, List(Severity.Warn, Severity.Error))
lazy val genPosition: Gen[Position] =
for {
line <- optIntGen
content <- genString
offset <- optIntGen
} yield InterfaceUtil.position(
line,
content,
offset,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
)
lazy val listDiagnosticRelatedInformation: Gen[List[DiagnosticRelatedInformation]] =
Gen.list(genDiagnosticRelatedInformation, Range.linear(0, 2))
lazy val genDiagnosticRelatedInformation: Gen[DiagnosticRelatedInformation] =
for {
pos <- genPosition
message <- genString
} yield InterfaceUtil.diagnosticRelatedInformation(pos, message)
lazy val listAction: Gen[List[Action]] =
Gen.list(genAction, Range.linear(0, 2))
lazy val genAction: Gen[Action] =
for {
title <- genString
description <- optString
edit <- genWorkspaceEdit
} yield InterfaceUtil.action(title, description, edit)
lazy val genWorkspaceEdit: Gen[WorkspaceEdit] =
for {
changes <- listTextEdit
} yield InterfaceUtil.workspaceEdit(changes)
lazy val listTextEdit: Gen[List[TextEdit]] =
Gen.list(genTextEdit, Range.linear(0, 2))
lazy val genTextEdit: Gen[TextEdit] =
for {
pos <- genPosition
newText <- genString
} yield InterfaceUtil.textEdit(pos, newText)
lazy val genUri: Gen[URI] =
for {
ssp <- genString
} yield new URI("file", "///" + ssp, null)
lazy val optString: Gen[Option[String]] =
Gen.choice1(genString.map(Some(_)), Gen.constant(None))
lazy val genString = Gen.string(Gen.alphaNum, Range.linear(0, 256))
lazy val optIntGen: Gen[Option[Integer]] =
Gen.choice1(Gen.int(Range.linear(0, 1024)).map(Some(_)), Gen.constant(None))
private def copy(c: DiagnosticCode): DiagnosticCode =
new DiagnosticCode() {
val code = c.code
override def explanation = c.explanation
}
private def copy(info: DiagnosticRelatedInformation): DiagnosticRelatedInformation =
new DiagnosticRelatedInformation() {
override def position = info.position
override def message = info.message
}
private def copy(a: Action): Action =
new Action {
override def title = a.title
override def description = a.description
override def edit = copy(a.edit)
}
private def copy(edit: WorkspaceEdit): WorkspaceEdit =
new WorkspaceEdit {
override def changes() =
l2jl(jl2l(edit.changes).map(copy))
}
private def copy(edit: TextEdit): TextEdit =
new TextEdit {
override val position = edit.position
override val newText = edit.newText
}
}