-
Philippe Suter authoredPhilippe Suter authored
AnalysisPhase.scala 4.87 KiB
package leon
package verification
import purescala.Common._
import purescala.Definitions._
import purescala.Trees._
import purescala.TreeOps._
import purescala.TypeTrees._
import solvers.{Solver,TrivialSolver}
import solvers.z3.FairZ3Solver
import scala.collection.mutable.{Set => MutableSet}
object AnalysisPhase extends LeonPhase[Program,VerificationReport] {
val name = "Analysis"
val description = "Leon Verification"
override def definedOptions = Set(
LeonFlagOptionDef("no-luck", "--no-luck", "Disable early model detection in solving loop.")
)
def run(ctx: LeonContext)(program: Program) : VerificationReport = {
val reporter = ctx.reporter
val trivialSolver = new TrivialSolver(ctx)
val fairZ3 = new FairZ3Solver(ctx)
val solvers : Seq[Solver] = trivialSolver :: fairZ3 :: Nil
solvers.foreach(_.setProgram(program))
val defaultTactic = new DefaultTactic(reporter)
defaultTactic.setProgram(program)
val inductionTactic = new InductionTactic(reporter)
inductionTactic.setProgram(program)
def generateVerificationConditions : List[VerificationCondition] = {
var allVCs: Seq[VerificationCondition] = Seq.empty
val analysedFunctions: MutableSet[String] = MutableSet.empty
for(funDef <- program.definedFunctions.toList.sortWith((fd1, fd2) => fd1 < fd2) if (Settings.functionsToAnalyse.isEmpty || Settings.functionsToAnalyse.contains(funDef.id.name))) {
analysedFunctions += funDef.id.name
val tactic: Tactic =
if(funDef.annotations.contains("induct")) {
inductionTactic
} else {
defaultTactic
}
if(funDef.body.isDefined) {
allVCs ++= tactic.generatePreconditions(funDef)
allVCs ++= tactic.generatePatternMatchingExhaustivenessChecks(funDef)
allVCs ++= tactic.generatePostconditions(funDef)
allVCs ++= tactic.generateMiscCorrectnessConditions(funDef)
allVCs ++= tactic.generateArrayAccessChecks(funDef)
}
allVCs = allVCs.sortWith((vc1, vc2) => {
val id1 = vc1.funDef.id.name
val id2 = vc2.funDef.id.name
if(id1 != id2) id1 < id2 else vc1 < vc2
})
}
val notFound: Set[String] = Settings.functionsToAnalyse -- analysedFunctions
notFound.foreach(fn => reporter.error("Did not find function \"" + fn + "\" though it was marked for analysis."))
allVCs.toList
}
def checkVerificationConditions(vcs: Seq[VerificationCondition]) : VerificationReport = {
for(vcInfo <- vcs) {
val funDef = vcInfo.funDef
val vc = vcInfo.condition
reporter.info("Now considering '" + vcInfo.kind + "' VC for " + funDef.id + "...")
reporter.info("Verification condition (" + vcInfo.kind + ") for ==== " + funDef.id + " ====")
reporter.info(simplifyLets(vc))
// try all solvers until one returns a meaningful answer
var superseeded : Set[String] = Set.empty[String]
solvers.find(se => {
reporter.info("Trying with solver: " + se.shortDescription)
if(superseeded(se.shortDescription) || superseeded(se.description)) {
reporter.info("Solver was superseeded. Skipping.")
false
} else {
superseeded = superseeded ++ Set(se.superseeds: _*)
val t1 = System.nanoTime
se.init()
val solverResult = se.solve(vc)
val t2 = System.nanoTime
val dt = ((t2 - t1) / 1000000) / 1000.0
solverResult match {
case None => false
case Some(true) => {
reporter.info("==== VALID ====")
vcInfo.value = Some(true)
vcInfo.solvedWith = Some(se)
vcInfo.time = Some(dt)
true
}
case Some(false) => {
reporter.error("==== INVALID ====")
vcInfo.value = Some(false)
vcInfo.solvedWith = Some(se)
vcInfo.time = Some(dt)
true
}
}
}
}) match {
case None => {
reporter.warning("No solver could prove or disprove the verification condition.")
}
case _ =>
}
}
val report = new VerificationReport(vcs)
reporter.info(report.summaryString)
report
}
// We generate all function templates in advance.
for(funDef <- program.definedFunctions if funDef.hasImplementation) {
// this gets cached :D
FunctionTemplate.mkTemplate(funDef)
}
val report = if(solvers.size > 1) {
reporter.info("Running verification condition generation...")
checkVerificationConditions(generateVerificationConditions)
} else {
reporter.warning("No solver specified. Cannot test verification conditions.")
VerificationReport.emptyReport
}
report
}
}