-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathworking.py
More file actions
135 lines (98 loc) · 3.69 KB
/
working.py
File metadata and controls
135 lines (98 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
from __future__ import (absolute_import, division, print_function)
import argparse
import libadalang as lal
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('files', help='The files to analyze',
type=str, nargs='+', metavar='F')
def location(node):
return (node.token_start._sloc_range.start.line,
node.token_start._sloc_range.start.column)
# Without semantic information, we cannot consider enumeration literals yet
def is_literal(expr):
return isinstance(expr, (lal.CharLiteral,
lal.StringLiteral,
lal.CharLiteral,
lal.IntLiteral,
lal.NullLiteral))
def list_left_unequal_operands(binop):
"""
List all the sub-operands of `binop`, as long as they have the same
operator as `binop`.
:type binop: lal.BinOp
"""
def list_sub_operands(expr, op):
"""
Accumulate sub-operands of `expr`, provided `expr` is a binary operator
that has `op` as an operator.
:type expr: lal.Expr
:type op: lal.Op
"""
if isinstance(expr, lal.BinOp) and type(expr.f_op) is type(op):
return (list_sub_operands(expr.f_left, op)
+ list_sub_operands(expr.f_right, op))
elif (isinstance(expr, lal.BinOp)
and isinstance(expr.f_op, lal.OpNeq)
and is_literal(expr.f_right)):
return [(expr.f_left, expr.f_right)]
else:
return []
op = binop.f_op
return (list_sub_operands(binop.f_left, op)
+ list_sub_operands(binop.f_right, op))
def tokens_text(node):
return tuple((t.kind, t.text) for t in node.tokens)
def has_same_operands(expr):
"""
For a logic relation, checks whether any combination of its sub-operands
are syntactically equivalent. If a duplicate operand is found, return it.
:rtype: lal.Expr|None
"""
ops = {}
all_ops = list_left_unequal_operands(expr)
if len(all_ops) > 1:
for op in all_ops:
(op_left, op_right) = op
tokens = tokens_text(op_left)
if tokens in ops:
return (op_left, ops[tokens], op_right)
ops[tokens] = op_right
def same_as_parent(binop):
"""
Checks whether binop is a BinOp with the same structure as its parent (same
operator).
:rtype: bool
"""
par = binop.parent
return (isinstance(binop, lal.BinOp)
and isinstance(par, lal.BinOp)
and type(binop.f_op) is type(par.f_op))
def interesting_oper(op):
"""
Check that op is a relational operator, which are the operators that
interrest us in the context of this script.
:rtype: bool
"""
return isinstance(op, (lal.OpOr, lal.OpOrElse))
def do_file(f):
c = lal.AnalysisContext()
unit = c.get_from_file(f)
if unit.root is None:
print('Could not parse {}:'.format(f))
for diag in unit.diagnostics:
print(' {}'.format(diag))
return
for binop in unit.root.findall(lal.BinOp):
if interesting_oper(binop.f_op) and not same_as_parent(binop):
res = has_same_operands(binop)
if res is not None:
op, fst_val, snd_val = res
line, col = location(op)
print('{}:{}:{}: expression is always true,'
' "{}" is always different from {} or {}'.format(
f, line, col, op.text, fst_val.text, snd_val.text))
#def main(args):
# for f in args.files:
# do_file(f)
do_file(GPS.File("nmea-messages-apa.ads").name())
#if __name__ == '__main__':
# main(parser.parse_args())