@@ -81,6 +81,19 @@ class Objects(using Context @constructorOnly):
8181 val allowList : Set [Symbol ] = Set (SetNode_EmptySetNode , HashSet_EmptySet , Vector_EmptyIterator , MapNode_EmptyMapNode , HashMap_EmptyMap ,
8282 ManifestFactory_ObjectTYPE , ManifestFactory_NothingTYPE , ManifestFactory_NullTYPE )
8383
84+ /**
85+ * Whether the analysis work in best-effort mode in contrast to aggressive mode.
86+ *
87+ * - In best-effort mode, the analysis tries to be fast, useful and unobtrusive.
88+ * - In the aggressive mode, the analysis tries to be sound and verbose by spending more check time.
89+ *
90+ * In both mode, there is a worst-case guarantee based on a quota on the
91+ * number of method calls in initializing a global object.
92+ *
93+ * We use a patch to set `BestEffort` to `false` in testing community projects.
94+ */
95+ val BestEffort : Boolean = true
96+
8497 // ----------------------------- abstract domain -----------------------------
8598
8699 /** Syntax for the data structure abstraction used in abstract domain:
@@ -370,8 +383,14 @@ class Objects(using Context @constructorOnly):
370383
371384 val hasError = ctx.reporter.pendingMessages.nonEmpty
372385 if cache.hasChanged && ! hasError then
373- cache.prepareForNextIteration()
374- iterate()
386+ if count <= 3 then
387+ cache.prepareForNextIteration()
388+ iterate()
389+ else
390+ if ! BestEffort then
391+ report.warning(" Giving up checking initializatino of " + classSym + " due to complex code" , classSym.sourcePos)
392+ data.checkedObjects += obj
393+ obj
375394 else
376395 data.checkedObjects += obj
377396 obj
@@ -959,15 +978,11 @@ class Objects(using Context @constructorOnly):
959978 if ! map.contains(sym) then map.updated(sym, value)
960979 else map.updated(sym, map(sym).join(value))
961980
962- /** Check if the checker option reports warnings about unknown code
963- */
964- val reportUnknown : Boolean = false
965-
966981 def reportWarningForUnknownValue (msg : => String , pos : SrcPos )(using Context ): Value =
967- if reportUnknown then
968- report.warning(msg, pos)
982+ if BestEffort then
969983 Bottom
970984 else
985+ report.warning(msg, pos)
971986 UnknownValue
972987
973988 /** Handle method calls `e.m(args)`.
@@ -1122,7 +1137,7 @@ class Objects(using Context @constructorOnly):
11221137 value
11231138 else
11241139 // In future, we will have Tasty for stdlib classes and can abstractly interpret that Tasty.
1125- // For now, return `UnknownValue` to ensure soundness and trigger a warning when reportUnknown = true .
1140+ // For now, return `UnknownValue` to ensure soundness and trigger a warning when BestEffort = false .
11261141 UnknownValue
11271142 end if
11281143 end if
0 commit comments