mirror of
				https://github.com/ethereum/solidity
				synced 2023-10-03 13:03:40 +00:00 
			
		
		
		
	Add a script to correct IDs
This commit is contained in:
		
							parent
							
								
									8f68c04358
								
							
						
					
					
						commit
						2d984b77a1
					
				| @ -38,6 +38,8 @@ namespace solidity::langutil | ||||
|  * They are passed as the first parameter of error reporting functions. | ||||
|  * Suffix _error helps to find them in the sources. | ||||
|  * The struct ErrorId prevents incidental calls like typeError(3141) instead of typeError(3141_error). | ||||
|  * To create a new ID, one can add 0000_error and then run "python ./scripts/correct_error_ids.py" | ||||
|  * from the root of the repo. | ||||
|  */ | ||||
| struct ErrorId { unsigned long long error = 0; }; | ||||
| ErrorId operator"" _error(unsigned long long error); | ||||
|  | ||||
							
								
								
									
										158
									
								
								scripts/correct_error_ids.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								scripts/correct_error_ids.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,158 @@ | ||||
| import random | ||||
| import re | ||||
| import os | ||||
| from os import path | ||||
| 
 | ||||
| ENCODING = "utf-8" | ||||
| PATTERN = r"\b\d+_error\b" | ||||
| 
 | ||||
| 
 | ||||
| def read_file(file_name): | ||||
|     content = None | ||||
|     try: | ||||
|         with open(file_name, "r", encoding=ENCODING) as f: | ||||
|             content = f.read() | ||||
|     finally: | ||||
|         if content == None: | ||||
|             print(f"Error reading: {file_name}") | ||||
|     return content | ||||
| 
 | ||||
| 
 | ||||
| def write_file(file_name, content): | ||||
|     with open(file_name, "w", encoding=ENCODING) as f: | ||||
|         f.write(content) | ||||
| 
 | ||||
| 
 | ||||
| def in_comment(source, pos): | ||||
|     slash_slash_pos = source.rfind("//", 0, pos) | ||||
|     lf_pos = source.rfind("\n", 0, pos) | ||||
|     if slash_slash_pos > lf_pos: | ||||
|         return True | ||||
|     slash_star_pos = source.rfind("/*", 0, pos) | ||||
|     star_slash_pos = source.rfind("*/", 0, pos) | ||||
|     return slash_star_pos > star_slash_pos | ||||
| 
 | ||||
| 
 | ||||
| def find_ids_in_file(file_name, ids): | ||||
|     source = read_file(file_name) | ||||
|     for m in re.finditer(PATTERN, source): | ||||
|         if in_comment(source, m.start()): | ||||
|             continue | ||||
|         underscore_pos = m.group(0).index("_") | ||||
|         id = m.group(0)[0:underscore_pos] | ||||
|         if id in ids: | ||||
|             ids[id] += 1 | ||||
|         else: | ||||
|             ids[id] = 1 | ||||
| 
 | ||||
| 
 | ||||
| def get_used_ids(file_names): | ||||
|     used_ids = {} | ||||
|     for file_name in file_names: | ||||
|         find_ids_in_file(file_name, used_ids) | ||||
|     return used_ids | ||||
| 
 | ||||
| 
 | ||||
| def get_id(available_ids, used_ids): | ||||
|     while len(available_ids) > 0: | ||||
|         random.seed(len(available_ids)) | ||||
|         k = random.randrange(len(available_ids)) | ||||
|         id = list(available_ids.keys())[k] | ||||
|         del available_ids[id] | ||||
|         if id not in used_ids: | ||||
|             return id | ||||
|     assert False, "Out of IDs" | ||||
| 
 | ||||
| 
 | ||||
| def fix_ids_in_file(file_name, available_ids, used_ids): | ||||
|     source = read_file(file_name) | ||||
| 
 | ||||
|     k = 0 | ||||
|     destination = [] | ||||
|     for m in re.finditer(PATTERN, source): | ||||
|         destination.extend(source[k:m.start()]) | ||||
| 
 | ||||
|         underscore_pos = m.group(0).index("_") | ||||
|         id = m.group(0)[0:underscore_pos] | ||||
| 
 | ||||
|         # incorrect id or id has a duplicate somewhere | ||||
|         if not in_comment(source, m.start()) and (len(id) != 4 or id[0] == "0" or used_ids[id] > 1): | ||||
|             assert id in used_ids | ||||
|             new_id = get_id(available_ids, used_ids) | ||||
|             used_ids[id] -= 1 | ||||
|         else: | ||||
|             new_id = id | ||||
| 
 | ||||
|         destination.extend(new_id + "_error") | ||||
|         k = m.end() | ||||
| 
 | ||||
|     destination.extend(source[k:]) | ||||
| 
 | ||||
|     destination = ''.join(destination) | ||||
|     if source != destination: | ||||
|         write_file(file_name, destination) | ||||
|         print(f"Fixed file: {file_name}") | ||||
| 
 | ||||
| 
 | ||||
| def fix_ids(used_ids, file_names): | ||||
|     available_ids = {str(id): None for id in range(1000, 10000)} | ||||
|     for file_name in file_names: | ||||
|         fix_ids_in_file(file_name, available_ids, used_ids) | ||||
| 
 | ||||
| 
 | ||||
| def find_source_files(top_dir): | ||||
|     """Builds the list of .h and .cpp files in top_dir directory""" | ||||
| 
 | ||||
|     source_file_names = [] | ||||
|     black_set = { ".circleci", ".git", ".github", "build", "cmake", "CMakeFiles", "deps", "docs" } | ||||
| 
 | ||||
|     for root, _, file_names in os.walk(top_dir, onerror=lambda e: exit(f"Walk error: {e}")): | ||||
|         path_elements = set(root.split(os.sep)) | ||||
|         if not black_set.isdisjoint(path_elements): | ||||
|             continue | ||||
|         for file_name in file_names: | ||||
|             _, ext = path.splitext(file_name) | ||||
|             if ext in [".h", ".cpp"]: | ||||
|                 source_file_names.append(path.join(root, file_name)) | ||||
| 
 | ||||
|     return source_file_names | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|     cwd = os.getcwd() | ||||
|     answer = input( | ||||
|         f"This script checks and corrects *_error literals in .h and .cpp files\n" | ||||
|         f"in {cwd}, recursively.\n\n" | ||||
|         f"Please commit current changes first, and review the results when the script finishes.\n\n" | ||||
|         f"Do you want to start [Y/N]? " | ||||
|     ) | ||||
|     while len(answer) == 0 or answer not in "YN": | ||||
|         answer = input("[Y/N]? ") | ||||
|     if answer != "Y": | ||||
|         return | ||||
| 
 | ||||
|     source_file_names = find_source_files(cwd) | ||||
| 
 | ||||
|     used_ids = get_used_ids(source_file_names) | ||||
| 
 | ||||
|     ok = True | ||||
|     for id in sorted(used_ids): | ||||
|         if len(id) != 4: | ||||
|             print(f"ID {id} length != 4") | ||||
|             ok = False | ||||
|         if id[0] == "0": | ||||
|             print(f"ID {id} starts with zero") | ||||
|             ok = False | ||||
|         if used_ids[id] > 1: | ||||
|             print(f"ID {id} appears {used_ids[id]} times") | ||||
|             ok = False | ||||
| 
 | ||||
|     if ok: | ||||
|         print("No incorrect IDs found") | ||||
|     else: | ||||
|         fix_ids(used_ids, source_file_names) | ||||
|         print("Fixing compteted") | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     main() | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user