@@ -313,13 +313,79 @@ class Node extends TIRDataFlowNode {
313313 * `n.asExpr() instanceof IncrementOperation` since the result of evaluating
314314 * the expression `x++` is passed to `sink`.
315315 */
316- Expr asDefinition ( ) {
317- exists ( StoreInstruction store |
316+ Expr asDefinition ( ) { result = this .asDefinition ( _) }
317+
318+ /**
319+ * Gets the definition associated with this node, if any.
320+ *
321+ * For example, consider the following example
322+ * ```cpp
323+ * int x = 42; // 1
324+ * x = 34; // 2
325+ * ++x; // 3
326+ * x++; // 4
327+ * x += 1; // 5
328+ * int y = x += 2; // 6
329+ * ```
330+ * - For (1) the result is `42`.
331+ * - For (2) the result is `x = 34`.
332+ * - For (3) the result is `++x`.
333+ * - For (4) the result is `x++`.
334+ * - For (5) the result is `x += 1`.
335+ * - For (6) there are two results:
336+ * - For the definition generated by `x += 2` the result is `x += 2`
337+ * - For the definition generated by `int y = ...` the result is
338+ * also `x += 2`.
339+ *
340+ * For assignments, `node.asDefinition(_)` and `node.asExpr()` will both exist
341+ * for the same dataflow node. However, for expression such as `x++` that
342+ * both write to `x` and read the current value of `x`, `node.asDefinition(_)`
343+ * will give the node corresponding to the value after the increment, and
344+ * `node.asExpr()` will give the node corresponding to the value before the
345+ * increment. For an example of this, consider the following:
346+ *
347+ * ```cpp
348+ * sink(x++);
349+ * ```
350+ * in the above program, there will not be flow from a node `n` such that
351+ * `n.asDefinition(_) instanceof IncrementOperation` to the argument of `sink`
352+ * since the value passed to `sink` is the value before to the increment.
353+ * However, there will be dataflow from a node `n` such that
354+ * `n.asExpr() instanceof IncrementOperation` since the result of evaluating
355+ * the expression `x++` is passed to `sink`.
356+ *
357+ * If `uncertain = false` then the definition is guaranteed to overwrite
358+ * the entire buffer pointed to by the destination address of the definition.
359+ * Otherwise, `uncertain = true`.
360+ *
361+ * For example, the write `int x; x = 42;` is guaranteed to overwrite all the
362+ * bytes allocated to `x`, while the assignment `int p[10]; p[3] = 42;` has
363+ * `uncertain = true` since the write will not overwrite the entire buffer
364+ * pointed to by `p`.
365+ */
366+ Expr asDefinition ( boolean uncertain ) {
367+ exists ( StoreInstruction store , Ssa:: DefinitionExt def |
318368 store = this .asInstruction ( ) and
319- result = asDefinitionImpl ( store )
369+ result = asDefinitionImpl ( store ) and
370+ Ssa:: defToNode ( this , def , _, _, _, _) and
371+ if def .isCertain ( ) then uncertain = false else uncertain = true
320372 )
321373 }
322374
375+ /**
376+ * Gets the definition associated with this node, if this node is a certain definition.
377+ *
378+ * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
379+ */
380+ Expr asCertainDefinition ( ) { result = this .asDefinition ( false ) }
381+
382+ /**
383+ * Gets the definition associated with this node, if this node is an uncertain definition.
384+ *
385+ * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
386+ */
387+ Expr asUncertainDefinition ( ) { result = this .asDefinition ( true ) }
388+
323389 /**
324390 * Gets the indirect definition at a given indirection corresponding to this
325391 * node, if any.
0 commit comments