Code-Inspect / flowr

A program slicer and dataflow analyzer for the R programming language.
https://github.com/Code-Inspect/flowr/wiki
GNU General Public License v3.0
14 stars 2 forks source link

Question: Inconclusive dataflow graph #810

Closed Ellpeck closed 1 month ago

Ellpeck commented 1 month ago
        assertDataflow(label('simple assign', ['assignment-functions', 'strings', 'implicit-return', 'normal-definition', 'newlines', 'call-normal', 'numbers']),
            shell, 'assign("a", function() 1)\na()', emptyGraph()
                .call('9', 'a', [], { returns: ['3'], reads: ['1'], environment: defaultEnv().defineFunction('a', '1', '7') })
                .calls('9', '5')
                .defineVariable('1', '"a"', { definedBy: ['7', '5'] })
                .call('7', 'assign', [argumentInCall('1'), argumentInCall('5')], { onlyBuiltIn: true })
                .defineFunction('5', ['3'], {
                    entryPoint:        '5',
                    environment:       defaultEnv().pushEnv(),
                    graph:             new Set(['3']),
                    in:                [{ nodeId: '3', name: undefined, controlDependencies: [] }],
                    out:               [],
                    unknownReferences: []
                })
                .constant('3', undefined, false)
        )

yields this mermaid comparison (which seems identical) along with this guard output:

 * Detected different number of edges! expected has 3 ([[9,[[3,{"types":8}],[1,{"types":1}],[5,{"types":4}]]],[1,[[7,{"types":2}],[5,{"types":2}]]],[7,[[1,{"types":64}],[5,{"types":64}]]]]). got has 4 [[7,[[5,{"types":64}],[1,{"types":64}]]],[1,[[5,{"types":2}],[7,{"types":2}]]],[0,[[1,{"types":8}],["built-in",{"types":1}]]],[9,[[1,{"types":1}],[3,{"types":8}],[5,{"types":4}]]]]
 * Vertex 0 has undefined outgoing edges. expected: undefined vs got: [[1,{"types":8}],["built-in",{"types":1}]]

I'm having trouble understanding what the edge number line means (as well as decyphering the actual edge output - maybe it would be nice if the comparison added line breaks or some type of highlighting there!), as well as the undefined outgoing edges, since no additional edges seem to be present in the dataflow graph - unless I'm really very blind.

Since this is a test for #800, there's also a chance that there is some actual error happening here. I'd generally expect it to be an issue of my understanding in this case, though.

Ellpeck commented 1 month ago

Similar situation with this code:

        assertDataflow(label('assign in condition', ['name-normal', 'lambda-syntax', 'numbers', 'if', 'newlines', 'assignment-functions', 'strings', 'normal-definition', 'implicit-return', 'call-normal']),
            shell, `a <- \\() 2
if(y) {
   assign("a", function() 1)
}
a()`,  emptyGraph()
                .use('5', 'y')
                .call('4', '<-', [argumentInCall('0'), argumentInCall('3')], { returns: ['0'], reads: [BuiltIn] })
                .argument('4', ['3', '0'])
                .call('15', 'assign', [argumentInCall('9'), argumentInCall('13')], { returns: [], reads: [], environment: defaultEnv().defineFunction('a', '0', '4'), onlyBuiltIn: true })
                .argument('15', ['13', '9'])
                .call('16', '{', [argumentInCall('8')], { returns: ['8'], reads: [BuiltIn], controlDependency: ['17'], environment: defaultEnv().defineFunction('a', '0', '4') })
                .argument('16', '8')
                .argument('17', '5')
                .argument('17', '16')
                .call('17', 'if', [argumentInCall('5'), argumentInCall('16'), EmptyArgument], { returns: ['16'], reads: ['5', BuiltIn], onlyBuiltIn: true, environment: defaultEnv().defineFunction('a', '0', '4', ['17']) })
                .call('19', 'a', [], { returns: ['1', '11'], reads: ['9', '0'], environment: defaultEnv().defineFunction('a', '9', '15', ['17']).defineFunction('a', '0', '4', ['17']) })
                .calls('19', ['3', '13'])
                .constant('1', undefined, false)
                .defineFunction('3', ['1'], {
                    out:               [],
                    in:                [{ nodeId: '1', name: undefined, controlDependencies: [] }],
                    unknownReferences: [],
                    entryPoint:        '1',
                    graph:             new Set(['1']),
                    environment:       defaultEnv().pushEnv()
                })
                .defineVariable('0', 'a', { definedBy: ['3', '4'] })
                .constant('11', undefined, false)
                .defineFunction('13', ['11'], {
                    out:               [],
                    in:                [{ nodeId: '11', name: undefined, controlDependencies: [] }],
                    unknownReferences: [],
                    entryPoint:        '11',
                    graph:             new Set(['11']),
                    environment:       defaultEnv().pushEnv()
                })
                .defineVariable('9', '"a"', { definedBy: ['13', '15'], controlDependency: ['17'] })
        )

which yields this mermaid and this report:

 * Detected different number of edges! expected has 7 ([[4,[[0,{"types":72}],[3,{"types":64}],["built-in",{"types":1}]]],[15,[[9,{"types":64}],[13,{"types":64}]]],[16,[[8,{"types":72}],["built-in",{"types":1}]]],[17,[[5,{"types":65}],[16,{"types":72}],["built-in",{"types":1}]]],[19,[[1,{"types":8}],[11,{"types":8}],[9,{"types":1}],[0,{"types":1}],[3,{"types":4}],[13,{"types":4}]]],[0,[[3,{"types":2}],[4,{"types":2}]]],[9,[[13,{"types":2}],[15,{"types":2}]]]]). got has 8 [[4,[[3,{"types":64}],[0,{"types":72}],["built-in",{"types":1}]]],[0,[[3,{"types":2}],[4,{"types":2}]]],[15,[[13,{"types":64}],[9,{"types":64}]]],[9,[[13,{"types":2}],[15,{"types":2}]]],[8,[[9,{"types":8}],["built-in",{"types":1}]]],[16,[[8,{"types":72}],["built-in",{"types":1}]]],[17,[[16,{"types":72}],[5,{"types":65}],["built-in",{"types":1}]]],[19,[[9,{"types":1}],[0,{"types":1}],[1,{"types":8}],[3,{"types":4}],[11,{"types":8}],[13,{"types":4}]]]]
 * Vertex 8 has undefined outgoing edges. expected: undefined vs got: [[9,{"types":8}],["built-in",{"types":1}]]