Adds support for inheritance in naming-convention of structure variables.

pull/238/head
rajeevgopalakrishna 6 years ago
parent f8a07a90e1
commit 54f3f26e8a
  1. 60
      utils/slither_format/format_naming_convention.py
  2. 7
      utils/slither_format/tests/test_data/naming_convention_structure.sol
  3. 16
      utils/slither_format/tests/test_naming_convention.py

@ -544,38 +544,42 @@ t']:(node.source_mapping['start']+node.source_mapping['length'])].split('=')[0])
@staticmethod @staticmethod
def create_patch_struct_uses(slither, patches, name, contract_name, in_file): def create_patch_struct_uses(slither, patches, name, contract_name, in_file):
for contract in slither.contracts: for contract in slither.contracts:
in_file_str = slither.source_code[in_file] if (contract.name == contract_name):
# Check state variables of struct type target_contract = contract
# To-do: Deep-check aggregate types (struct and mapping) for contract in slither.contracts:
svs = contract.variables if (contract == target_contract or (contract in target_contract.derived_contracts)):
for sv in svs: in_file_str = slither.source_code[in_file]
if (str(sv.type) == contract_name + "." + name): # Check state variables of struct type
old_str_of_interest = in_file_str[sv.source_mapping['start']:(sv.source_mapping['start']+sv.source_mapping['length'])] # To-do: Deep-check aggregate types (struct and mapping)
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(),old_str_of_interest, 1) svs = contract.variables
patch = { for sv in svs:
"detector" : "naming-convention (struct use)", if (str(sv.type) == contract_name + "." + name):
"start" : sv.source_mapping['start'], old_str_of_interest = in_file_str[sv.source_mapping['start']:(sv.source_mapping['start']+sv.source_mapping['length'])]
"end" : sv.source_mapping['start'] + sv.source_mapping['length'],
"old_string" : old_str_of_interest,
"new_string" : new_str_of_interest
}
if not patch in patches[in_file]:
patches[in_file].append(patch)
# Check function+modifier locals+parameters+returns
# To-do: Deep-check aggregate types (struct and mapping)
fms = contract.functions + contract.modifiers
for fm in fms:
for v in fm.variables:
if (str(v.type) == contract_name + "." + name):
old_str_of_interest = in_file_str[v.source_mapping['start']:(v.source_mapping['start']+v.source_mapping['length'])]
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(),old_str_of_interest, 1) (new_str_of_interest, num_repl) = re.subn(name, name.capitalize(),old_str_of_interest, 1)
patch = { patch = {
"detector" : "naming-convention (struct use)", "detector" : "naming-convention (struct use)",
"start" : v.source_mapping['start'], "start" : sv.source_mapping['start'],
"end" : v.source_mapping['start'] + v.source_mapping['length'], "end" : sv.source_mapping['start'] + sv.source_mapping['length'],
"old_string" : old_str_of_interest, "old_string" : old_str_of_interest,
"new_string" : new_str_of_interest "new_string" : new_str_of_interest
} }
if not patch in patches[in_file]: if not patch in patches[in_file]:
patches[in_file].append(patch) patches[in_file].append(patch)
# To-do: Check any other place/way where struct type is used (e.g. typecast) # Check function+modifier locals+parameters+returns
# To-do: Deep-check aggregate types (struct and mapping)
fms = contract.functions + contract.modifiers
for fm in fms:
for v in fm.variables:
if (str(v.type) == contract_name + "." + name):
old_str_of_interest = in_file_str[v.source_mapping['start']:(v.source_mapping['start']+v.source_mapping['length'])]
(new_str_of_interest, num_repl) = re.subn(name, name.capitalize(),old_str_of_interest, 1)
patch = {
"detector" : "naming-convention (struct use)",
"start" : v.source_mapping['start'],
"end" : v.source_mapping['start'] + v.source_mapping['length'],
"old_string" : old_str_of_interest,
"new_string" : new_str_of_interest
}
if not patch in patches[in_file]:
patches[in_file].append(patch)
# To-do: Check any other place/way where struct type is used (e.g. typecast)

@ -49,3 +49,10 @@ contract C {
} }
} }
contract D is C {
/* struct as parameter and return value - bad */
function foo(s sA) returns (s) {
s1.i = sA.i;
return (s1);
}
}

@ -185,9 +185,9 @@ class TestNamingConvention(unittest.TestCase):
outFD3_lines[i] = outFD3_lines[i].strip() outFD3_lines[i] = outFD3_lines[i].strip()
self.assertTrue(os.path.isfile(self.testFilePath3+".format"),"Patched .format file is not created?!") self.assertTrue(os.path.isfile(self.testFilePath3+".format"),"Patched .format file is not created?!")
self.assertEqual(outFD3_lines[0],"Number of Slither results: 2") self.assertEqual(outFD3_lines[0],"Number of Slither results: 2")
self.assertEqual(outFD3_lines[1],"Number of patches: 6") self.assertEqual(outFD3_lines[1],"Number of patches: 8")
self.assertEqual(outFD3_lines.count("Detector: naming-convention (struct definition)"), 2) self.assertEqual(outFD3_lines.count("Detector: naming-convention (struct definition)"), 2)
self.assertEqual(outFD3_lines.count("Detector: naming-convention (struct use)"), 4) self.assertEqual(outFD3_lines.count("Detector: naming-convention (struct use)"), 6)
self.assertEqual(outFD3_lines.count("Old string: struct s { uint i; }"), 2) self.assertEqual(outFD3_lines.count("Old string: struct s { uint i; }"), 2)
self.assertEqual(outFD3_lines.count("New string: struct S { uint i; }"), 2) self.assertEqual(outFD3_lines.count("New string: struct S { uint i; }"), 2)
self.assertEqual(outFD3_lines.count("Location start: 108"), 1) self.assertEqual(outFD3_lines.count("Location start: 108"), 1)
@ -200,14 +200,18 @@ class TestNamingConvention(unittest.TestCase):
self.assertEqual(outFD3_lines.count("Location end: 175"), 1) self.assertEqual(outFD3_lines.count("Location end: 175"), 1)
self.assertEqual(outFD3_lines.count("Location start: 497"), 1) self.assertEqual(outFD3_lines.count("Location start: 497"), 1)
self.assertEqual(outFD3_lines.count("Location end: 501"), 1) self.assertEqual(outFD3_lines.count("Location end: 501"), 1)
self.assertEqual(outFD3_lines.count("Old string: s sA"), 1) self.assertEqual(outFD3_lines.count("Old string: s sA"), 2)
self.assertEqual(outFD3_lines.count("New string: S sA"), 1) self.assertEqual(outFD3_lines.count("New string: S sA"), 2)
self.assertEqual(outFD3_lines.count("Location start: 570"), 1) self.assertEqual(outFD3_lines.count("Location start: 570"), 1)
self.assertEqual(outFD3_lines.count("Location end: 574"), 1) self.assertEqual(outFD3_lines.count("Location end: 574"), 1)
self.assertEqual(outFD3_lines.count("Old string: s"), 1) self.assertEqual(outFD3_lines.count("Location start: 715"), 1)
self.assertEqual(outFD3_lines.count("New string: S"), 1) self.assertEqual(outFD3_lines.count("Location end: 719"), 1)
self.assertEqual(outFD3_lines.count("Old string: s"), 2)
self.assertEqual(outFD3_lines.count("New string: S"), 2)
self.assertEqual(outFD3_lines.count("Location start: 585"), 1) self.assertEqual(outFD3_lines.count("Location start: 585"), 1)
self.assertEqual(outFD3_lines.count("Location end: 586"), 1) self.assertEqual(outFD3_lines.count("Location end: 586"), 1)
self.assertEqual(outFD3_lines.count("Location start: 730"), 1)
self.assertEqual(outFD3_lines.count("Location end: 731"), 1)
def test_naming_convention_enum(self): def test_naming_convention_enum(self):
outFD4 = open(self.testFilePath4+".out","r") outFD4 = open(self.testFilePath4+".out","r")

Loading…
Cancel
Save