You've already forked libadalang
mirror of
https://github.com/AdaCore/libadalang.git
synced 2026-02-12 12:28:54 -08:00
This attribute is not part of the public API and so may change without notice in Libadalang/Langkit refactorings. TN: UA19-026
87 lines
2.1 KiB
Python
Executable File
87 lines
2.1 KiB
Python
Executable File
#! /usr/bin/env python
|
|
|
|
"""
|
|
This script will detect syntactically identical expressions which are chained
|
|
together in a chain of logical operators in the input Ada sources.
|
|
"""
|
|
|
|
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)
|
|
|
|
|
|
def list_tests(ifnode):
|
|
"""
|
|
List all the tests of `ifnode`.
|
|
|
|
:type ifnode: lal.IfStmt|lal.IfExpr
|
|
"""
|
|
return [ifnode.f_cond_expr] + [
|
|
f.f_cond_expr for f in ifnode.f_alternatives
|
|
]
|
|
|
|
|
|
def tokens_text(node):
|
|
return tuple((t.kind, t.text) for t in node.tokens)
|
|
|
|
|
|
def one_liner(node):
|
|
return ''.join(map(lambda t: t.text, node.tokens))
|
|
|
|
|
|
def has_same_tests(expr):
|
|
"""
|
|
For an if-statement or an if-expression, checks whether any combination of
|
|
its tests are syntactically equivalent. If duplicate operands are found,
|
|
return them.
|
|
|
|
:rtype: lal.Expr|None
|
|
"""
|
|
tests = {}
|
|
all_tests = list_tests(expr)
|
|
if len(all_tests) > 1:
|
|
for test in all_tests:
|
|
tokens = tokens_text(test)
|
|
if tokens in tests:
|
|
return (tests[tokens], test)
|
|
tests[tokens] = test
|
|
|
|
|
|
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 ifnode in unit.root.findall((lal.IfStmt, lal.IfExpr)):
|
|
res = has_same_tests(ifnode)
|
|
if res is not None:
|
|
fst_test, snd_test = res
|
|
fst_line, fst_col = location(fst_test)
|
|
snd_line, snd_col = location(snd_test)
|
|
print('{}:{}:{}: duplicate test with line {}'.format(
|
|
f, snd_line, snd_col, fst_line
|
|
))
|
|
|
|
|
|
def main(args):
|
|
for f in args.files:
|
|
do_file(f)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main(parser.parse_args())
|