/** * @name Confusing method names because of overriding * @description Finds methods m1 and m2, where m1 would override m2, except that * their names differ in capitalization. * @kind problem * @problem.severity recommendation * @precision medium * @id cs/confusing-override-name * @tags reliability * readability * naming */ import csharp predicate hasSubtypeStar(RefType t, RefType u) { t = u or u.getABaseType+() = t } /** for each class, get all methods from this class or its superclasses, with their names in lowercase */ predicate methodNames(RefType t, Method m, string lowercase) { exists(RefType t2 | m.getDeclaringType() = t2 and hasSubtypeStar(t2, t) ) and lowercase = m.getName().toLowerCase() and lowercase.length() > 1 } /** For each class, find the pairs of methods that are candidates for being confusing in this class */ predicate confusing(Method m1, Method m2) { exists(RefType t, string lower | methodNames(t, m1, lower) and methodNames(t, m2, lower) and m1.getName() != m2.getName() ) } /* Two method names are confusing if all of the following conditions hold: * They are both static methods or both instance methods. * They are not declared in the same class, and the superclass method is * not overridden in an intermediate class * They have different names. * They have the same names if case is ignored. * There is no method in the subclass that has the same name as * the superclass method There is an additional check that only methods with names longer than one character can be considered confusing. */ from Method m1, Method m2 where confusing(m1,m2) and m1.getDeclaringType() != m2.getDeclaringType() and ( m1.isStatic() and m2.isStatic() or not m1.isStatic() and not m2.isStatic() ) and not exists(Method mid | confusing(m1, mid) and mid.getDeclaringType().getABaseType+() = m2.getDeclaringType() ) and not exists(Method notConfusing | notConfusing.getDeclaringType() = m1.getDeclaringType() and notConfusing.getName() = m2.getName() ) and m1.fromSource() select m1, "confusing to have methods " + m1.getName() + " in " + m1.getDeclaringType().getName() + " and " + m2.getName() + " in " + m2.getDeclaringType().getName() + "."