def translation_unit_based_rule(translation_unit): violations = [] for token in translation_unit.cursor.walk_preorder(): violation = checker.extract_violation(token, ID, f"{MSG} for {translation_unit.spelling}") if violation: violations.append(violation) return violations
def translation_unit_based_rule(translation_unit): """Checks for nested namespaces in one translation unit""" violations = [] nested_namespaces = defaultdict(list) # Set up a list of nested namspaces for token in translation_unit.cursor.walk_preorder(): if token.kind == cindex.CursorKind.NAMESPACE: if token.is_definition(): if token.location.file.name == translation_unit.spelling: # TODO Consider use a child-token traversal # The decision about the nesting level of namespace can # be derived from the clang naming count of a special token number_of_nestings = token.get_usr().count("@N") if number_of_nestings > MAX_DEPTH_ALLOWED: nested_namespaces[token.spelling].append( (token, number_of_nestings)) # Create violations based on nested namespaces found for _, nestings_per_namespace in nested_namespaces.items(): for nesting_per_namespace, number_of_nestings in nestings_per_namespace: violation = checker.extract_violation( nesting_per_namespace, ID, f"Multiple of {number_of_nestings} nested namespace(s) in one translation unit", ) if violation: violations.append(violation) return violations
def token_based_rule(token): """Checks whether an upper case "u" is provided for unsigned int literals""" violation = None if token.kind == cindex.CursorKind.INTEGER_LITERAL: if token.type.spelling == "unsigned int": for child_token in token.get_tokens(): if "u" in child_token.spelling: violation = checker.extract_violation( child_token, ID, "Lower Case suffix for unsigned integer") return violation
def check_for_clang_warnings(translation_unit): """Interprets clang diagnostics warnings (aka compiler warnings) as violations The checker differs from the other ones as it operates on the translation unit directly""" violations = [] checker.log_progress_for_checker(translation_unit, __name__) for diagnostic in translation_unit.diagnostics: if diagnostic.option and diagnostic.location.file: if diagnostic.option.startswith("-W"): the_id = ID_PREFIX + diagnostic.option[2:].upper().replace( "-", "_") violation = checker.extract_violation(diagnostic, the_id, diagnostic.spelling) violations.append(violation) return violations
def translation_unit_based_rule(translation_unit): violations = [] classes = [] for token in translation_unit.cursor.walk_preorder(): if token.kind == cindex.CursorKind.CLASS_DECL: if token.is_definition(): if token.location.file.name == translation_unit.spelling: classes.append(token) for the_class in classes: computed_name, basename = compute_expected_name( the_class, translation_unit.spelling) if computed_name != basename: violation = checker.extract_violation( the_class, ID, f"File name should be named '{computed_name}' as derived from the class '{the_class.spelling}'", ) if violation: violations.append(violation) return violations
def translation_unit_based_rule(translation_unit): """Checks for multiple classes in one translation unit""" violations = [] classes = [] for token in translation_unit.cursor.walk_preorder(): if token.kind == cindex.CursorKind.CLASS_DECL: if token.is_definition(): if token.location.file.name == translation_unit.spelling: classes.append(token) if len(classes) > ALLOWED_NUMBER_OF_CLASSES_PER_FILE: for the_class_token in classes: violation = checker.extract_violation( the_class_token, ID, f"Multiple of {len(classes)} classes 'class {the_class_token.spelling}' in one translation unit", ) if violation: violations.append(violation) return violations
def translation_unit_based_rule(translation_unit): """Find variable declrations which could be made const""" # TODO Check usage of a variable when handing over as a non-const reference violations = [] # All non-const variable declaration are suspected to be read-only all_non_const_variable_declarations = {} for token in translation_unit.cursor.walk_preorder(): if token.kind == cindex.CursorKind.VAR_DECL: if not token.type.is_const_qualified(): all_non_const_variable_declarations[hash(token)] = token # Check which of those variable declarations are being used as a reference in a binary operation (:= written) for token in translation_unit.cursor.walk_preorder(): referenced = check_references(token) if referenced: all_non_const_variable_declarations[hash(referenced)] = None if (token.kind == cindex.CursorKind.BINARY_OPERATOR or token.kind == cindex.CursorKind.UNARY_OPERATOR or token.kind == cindex.CursorKind.COMPOUND_ASSIGNMENT_OPERATOR): for child in token.get_children(): if child.kind == cindex.CursorKind.DECL_REF_EXPR: if child.referenced: for reference in child.referenced.walk_preorder(): if reference.kind == cindex.CursorKind.VAR_DECL: all_non_const_variable_declarations[hash( reference)] = None # Create violations based on non-const read-only variables # If the used token is not None, we have a violation for _, the_used_token in all_non_const_variable_declarations.items(): if the_used_token: violation = checker.extract_violation( the_used_token, ID, f"The variable '{the_used_token.spelling}' could be made const", ) if violation: violations.append(violation) return violations
def token_based_rule(token): violation = None violation = checker.extract_violation(token, ID, f"{MSG} for {token.spelling}") return violation