@@ -6,6 +6,9 @@ import viper.silicon.interfaces.state.{Chunk, GeneralChunk}
66import viper .silicon .state .terms ._
77import viper .silicon .verifier .Verifier
88import viper .silver .ast
9+ import viper .silver .ast .utility .Expressions .isKnownWellDefined
10+ import viper .silver .ast .{Apply , Applying , Assert , Asserting , Assume , Div , Exhale , Exp , ExtensionStmt , FieldAccess , FieldAccessPredicate , FieldAssign , Fold , FuncApp , Goto , If , Inhale , Label , LocalVarAssign , LocalVarDeclStmt , MapLookup , MethodCall , Mod , NewStmt , Package , Program , Quasihavoc , Quasihavocall , SeqIndex , Seqn , Stmt , Unfold , Unfolding , While }
11+ import viper .silver .ast .utility .{Expressions , ViperStrategy }
912
1013import java .util .concurrent .atomic .AtomicLong
1114import scala .collection .mutable
@@ -37,8 +40,8 @@ trait DependencyAnalyzer {
3740 def registerExhaleChunk [CH <: GeneralChunk ](sourceChunks : Set [Chunk ], buildChunk : Term => CH , perm : Term , labelNodeOpt : Option [LabelNode ], analysisInfo : AnalysisInfo ): CH = buildChunk(perm)
3841 def createLabelNode (label : Var , sourceChunks : Iterable [Chunk ], sourceTerms : Iterable [Term ]): Option [LabelNode ]
3942
40- def createAssertOrCheckNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo , isCheck : Boolean ): Option [GeneralAssertionNode ]
41- def addAssertFalseNode (isCheck : Boolean , assumptionType : AssumptionType , sourceInfo : AnalysisSourceInfo ): Option [Int ]
43+ def createAssertOrCheckNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo , isCheck : Boolean , isJoinNode : Boolean ): Option [GeneralAssertionNode ]
44+ def addAssertFalseNode (isCheck : Boolean , assumptionType : AssumptionType , sourceInfo : AnalysisSourceInfo , isJoinNode : Boolean ): Option [Int ]
4245 def addInfeasibilityNode (isCheck : Boolean , sourceInfo : AnalysisSourceInfo , assumptionType : AssumptionType ): Option [Int ]
4346
4447 def addDependency (source : Option [Int ], dest : Option [Int ]): Unit
@@ -60,14 +63,14 @@ trait DependencyAnalyzer {
6063 /**
6164 * Adds an assertion and assumption node with the given analysis source info and dependencies to the current infeasibility node.
6265 */
63- def addAssertionWithDepToInfeasNode (infeasNodeId : Option [Int ], analysisSourceInfo : AnalysisSourceInfo , dependencyType : DependencyType ): Unit = {}
66+ def addAssertionWithDepToInfeasNode (infeasNodeId : Option [Int ], analysisSourceInfo : AnalysisSourceInfo , dependencyType : DependencyType , isJoinNode : Boolean ): Unit = {}
6467
6568 /**
6669 * @return the final dependency graph representing all direct and transitive dependencies
6770 */
6871 def buildFinalGraph (): Option [DependencyGraph ]
6972
70- def addAssertionFailedNode (failedAssertion : Term , assertionType : AssumptionType , sourceInfo : AnalysisSourceInfo ): Option [Int ]
73+ def addAssertionFailedNode (failedAssertion : Term , assertionType : AssumptionType , sourceInfo : AnalysisSourceInfo , isJoinNode : Boolean ): Option [Int ]
7174}
7275
7376object DependencyAnalyzer {
@@ -229,12 +232,56 @@ object DependencyAnalyzer {
229232 else newGraph.addEdges(src, targets)
230233 }
231234
235+ val relevantAssertionNodes = joinCandidateAssertions // method call pres assertions
236+ .filter(_.isJoinNode)
237+ .groupBy(_.sourceInfo.getFineGrainedSource)
238+ .view.mapValues(_.map(_.id))
239+ .toMap
240+ joinCandidateNodes
241+ .map(node => (node.id, relevantAssertionNodes.getOrElse(node.sourceInfo.getTopLevelSource, Seq .empty)))
242+ .foreach { case (target, sources) =>
243+ if (customInternalNodes.intersect(sources.toSet.union(Set (target))).isEmpty) newGraph.addEdgesConnectingMethods(sources, target)
244+ else newGraph.addEdges(sources, target)
245+ }
246+
232247
233248 stopTimeMeasurementAndAddToTotal(startTime, timeForMethodJoin)
234249
235250 val newInterpreter = new DependencyGraphInterpreter (name, newGraph, dependencyGraphInterpreters.toList.flatMap(_.getErrors))
236251 newInterpreter
237252 }
253+
254+ def extractAssertionsForJoin (exp : ast.Exp , program : ast.Program ): Seq [ast.Exp ] = {
255+ exp match {
256+ case FieldAccessPredicate (FieldAccess (rcv, _), prm) =>
257+ // Extra case for field access predicates because the contained field access does NOT require already having the field permission.
258+ extractAssertionsForJoin(rcv, program) ++ extractAssertionsForJoin(prm.get, program)
259+ case f : FuncApp =>
260+ program.findFunction(f.funcname).pres
261+ case other => other.subExps.flatMap(extractAssertionsForJoin(_, program))
262+ }
263+ }
264+
265+ def extractAssertionsForJoin (s : Stmt , p : Program ): Seq [ast.Exp ] = {
266+ def goE (exp : Exp ): Seq [ast.Exp ] = extractAssertionsForJoin(exp, p)
267+
268+ def goEs (exps : Seq [Exp ]): Seq [ast.Exp ] = exps flatMap goE
269+
270+ s match {
271+ case NewStmt (lhs, _) => goE(lhs)
272+ case LocalVarAssign (lhs, rhs) => goE(lhs) ++ goE(rhs)
273+ case MethodCall (methodName, args, targets) =>
274+ p.findMethod(methodName).pres.flatMap(_.topLevelConjuncts) ++ goEs(args) ++ goEs(targets)
275+ case Inhale (exp) => goE(exp)
276+ case Assume (exp) => goE(exp)
277+ case Seqn (ss, _) => ss flatMap (extractAssertionsForJoin(_, p))
278+ case If (cond, thn, els) => goE(cond) ++ extractAssertionsForJoin(thn, p) ++ extractAssertionsForJoin(els, p)
279+ case While (cond, invs, body) => goEs(invs) ++ goE(cond) ++ extractAssertionsForJoin(body, p)
280+ case Label (_, invs) => goEs(invs)
281+ case _ => goEs(s.subnodes.filter(_.isInstanceOf [ast.Exp ]).map(
282+ _.asInstanceOf [ast.Exp ]))
283+ }
284+ }
238285}
239286
240287class DefaultDependencyAnalyzer (member : ast.Member ) extends DependencyAnalyzer {
@@ -333,21 +380,21 @@ class DefaultDependencyAnalyzer(member: ast.Member) extends DependencyAnalyzer {
333380 }
334381
335382 // adding assertion nodes
336- override def createAssertOrCheckNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo , isCheck : Boolean ): Option [GeneralAssertionNode ] = {
383+ override def createAssertOrCheckNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo , isCheck : Boolean , isJoinNode : Boolean ): Option [GeneralAssertionNode ] = {
337384 if (isCheck)
338- Some (SimpleCheckNode (term, assumptionType, analysisSourceInfo, isClosed_))
385+ Some (SimpleCheckNode (term, assumptionType, analysisSourceInfo, isClosed_, isJoinNode = isJoinNode ))
339386 else
340- Some (SimpleAssertionNode (term, assumptionType, analysisSourceInfo, isClosed_))
387+ Some (SimpleAssertionNode (term, assumptionType, analysisSourceInfo, isClosed_, isJoinNode = isJoinNode ))
341388 }
342389
343- def addAssertNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo ): Option [Int ] = {
344- val node = createAssertOrCheckNode(term, assumptionType, analysisSourceInfo, isCheck= false )
390+ def addAssertNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo , isJoinNode : Boolean ): Option [Int ] = {
391+ val node = createAssertOrCheckNode(term, assumptionType, analysisSourceInfo, isCheck= false , isJoinNode = isJoinNode )
345392 node foreach addAssertionNode
346393 node map (_.id)
347394 }
348395
349- override def addAssertFalseNode (isCheck : Boolean , assumptionType : AssumptionType , sourceInfo : AnalysisSourceInfo ): Option [Int ] = {
350- val node = createAssertOrCheckNode(False , assumptionType, sourceInfo, isCheck)
396+ override def addAssertFalseNode (isCheck : Boolean , assumptionType : AssumptionType , sourceInfo : AnalysisSourceInfo , isJoinNode : Boolean ): Option [Int ] = {
397+ val node = createAssertOrCheckNode(False , assumptionType, sourceInfo, isCheck, isJoinNode )
351398 addAssertionNode(node.get)
352399 node.map(_.id)
353400 }
@@ -358,10 +405,10 @@ class DefaultDependencyAnalyzer(member: ast.Member) extends DependencyAnalyzer {
358405 Some (node.id)
359406 }
360407
361- override def addAssertionFailedNode (failedAssertion : Term , assertionType : AssumptionType , sourceInfo : AnalysisSourceInfo ): Option [Int ] = {
408+ override def addAssertionFailedNode (failedAssertion : Term , assertionType : AssumptionType , sourceInfo : AnalysisSourceInfo , isJoinNode : Boolean ): Option [Int ] = {
362409 val assumptionType = if (AssumptionType .postconditionTypes.contains(assertionType)) AssumptionType .ExplicitPostcondition else AssumptionType .Explicit
363- val assumeNode = SimpleAssumptionNode (failedAssertion, None , sourceInfo, assumptionType, isClosed= false , isJoinNode= false )
364- val assertFailedNode = SimpleAssertionNode (failedAssertion, assertionType, sourceInfo, isClosed= false , hasFailed= true )
410+ val assumeNode = SimpleAssumptionNode (failedAssertion, None , sourceInfo, assumptionType, isClosed= false , isJoinNode= isJoinNode )
411+ val assertFailedNode = SimpleAssertionNode (failedAssertion, assertionType, sourceInfo, isClosed= false , hasFailed= true , isJoinNode = isJoinNode )
365412 dependencyGraph.addNode(assumeNode)
366413 dependencyGraph.addNode(assertFailedNode)
367414 dependencyGraph.addEdges(Set (assumeNode.id), assertFailedNode.id)
@@ -412,8 +459,8 @@ class DefaultDependencyAnalyzer(member: ast.Member) extends DependencyAnalyzer {
412459 }
413460
414461 override def addDependenciesForAbstractMembers (sourceExps : Seq [ast.Exp ], targetExps : Seq [ast.Exp ], postConditionType : AssumptionType = AssumptionType .ExplicitPostcondition ): Unit = {
415- val sourceNodeIds = sourceExps.flatMap(e => addAssumption(True , AnalysisSourceInfo .createAnalysisSourceInfo(e), AssumptionType .Precondition , isJoinNode= false , None ))
416- val targetNodes = targetExps.flatMap(e => addAssertNode(True , postConditionType, AnalysisSourceInfo .createAnalysisSourceInfo(e)))
462+ val sourceNodeIds = sourceExps.flatMap(e => addAssumption(True , AnalysisSourceInfo .createAnalysisSourceInfo(e), AssumptionType .Precondition , isJoinNode= true , None ))
463+ val targetNodes = targetExps.flatMap(e => addAssertNode(True , postConditionType, AnalysisSourceInfo .createAnalysisSourceInfo(e), isJoinNode = true ))
417464 dependencyGraph.addEdges(sourceNodeIds, targetNodes)
418465 }
419466
@@ -500,8 +547,8 @@ class DefaultDependencyAnalyzer(member: ast.Member) extends DependencyAnalyzer {
500547 * Adds an assertion node with the given analysis source info and dependencies to the current infeasibility node.
501548 * The resulting assertion node is required to detect dependencies of the source statement/expression on infeasible paths.
502549 */
503- override def addAssertionWithDepToInfeasNode (infeasNodeId : Option [Int ], analysisSourceInfo : AnalysisSourceInfo , dependencyType : DependencyType ): Unit = {
504- val newAssertionNodeId = addAssertNode(False , dependencyType.assertionType, analysisSourceInfo)
550+ override def addAssertionWithDepToInfeasNode (infeasNodeId : Option [Int ], analysisSourceInfo : AnalysisSourceInfo , dependencyType : DependencyType , isJoinNode : Boolean ): Unit = {
551+ val newAssertionNodeId = addAssertNode(False , dependencyType.assertionType, analysisSourceInfo, isJoinNode )
505552 addDependency(infeasNodeId, newAssertionNodeId)
506553 }
507554
@@ -523,10 +570,10 @@ class NoDependencyAnalyzer extends DependencyAnalyzer {
523570 override def addAxiom (assumption : Term , analysisSourceInfo : AnalysisSourceInfo , assumptionType : AssumptionType , description : Option [String ]): Option [Int ] = None
524571 override def createLabelNode (labelTerm : Var , sourceChunks : Iterable [Chunk ], sourceTerms : Iterable [Term ]): Option [LabelNode ] = None
525572
526- override def createAssertOrCheckNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo , isCheck : Boolean ): Option [GeneralAssertionNode ] = None
527- override def addAssertFalseNode (isCheck : Boolean , assumptionType : AssumptionType , sourceInfo : AnalysisSourceInfo ): Option [Int ] = None
573+ override def createAssertOrCheckNode (term : Term , assumptionType : AssumptionType , analysisSourceInfo : AnalysisSourceInfo , isCheck : Boolean , isJoinNode : Boolean ): Option [GeneralAssertionNode ] = None
574+ override def addAssertFalseNode (isCheck : Boolean , assumptionType : AssumptionType , sourceInfo : AnalysisSourceInfo , isJoinNode : Boolean ): Option [Int ] = None
528575 override def addInfeasibilityNode (isCheck : Boolean , sourceInfo : AnalysisSourceInfo , assumptionType : AssumptionType ): Option [Int ] = None
529- override def addAssertionFailedNode (failedAssertion : Term , assertionType : AssumptionType , sourceInfo : AnalysisSourceInfo ): Option [Int ] = None
576+ override def addAssertionFailedNode (failedAssertion : Term , assertionType : AssumptionType , sourceInfo : AnalysisSourceInfo , isJoinNode : Boolean ): Option [Int ] = None
530577
531578 override def addDependency (source : Option [Int ], dest : Option [Int ]): Unit = {}
532579 override def processUnsatCoreAndAddDependencies (dep : String , assertionLabel : String ): Unit = {}
0 commit comments