diff --git a/infer/src/checkers/patternMatch.ml b/infer/src/checkers/patternMatch.ml index 77b7d7efc..116543a94 100644 --- a/infer/src/checkers/patternMatch.ml +++ b/infer/src/checkers/patternMatch.ml @@ -330,14 +330,15 @@ let proc_calls resolve_attributes pdesc filter : (Procname.t * ProcAttributes.t) IList.rev !res let override_exists f tenv proc_name = - let super_type_exists tenv super_class_name = + let rec super_type_exists tenv super_class_name = let super_proc_name = Procname.replace_class proc_name (Typename.name super_class_name) in match Tenv.lookup tenv super_class_name with - | Some ({ methods }) -> + | Some ({ methods; supers; }) -> let is_override pname = Procname.equal pname super_proc_name && not (Procname.is_constructor pname) in - IList.exists (fun pname -> is_override pname && f pname) methods + IList.exists (fun pname -> is_override pname && f pname) methods || + IList.exists (super_type_exists tenv) supers | _ -> false in match proc_name with diff --git a/infer/tests/codetoanalyze/java/checkers/ExpensiveInterfaceExample.java b/infer/tests/codetoanalyze/java/checkers/ExpensiveInterfaceExample.java index 882e01135..5b1d6eefd 100644 --- a/infer/tests/codetoanalyze/java/checkers/ExpensiveInterfaceExample.java +++ b/infer/tests/codetoanalyze/java/checkers/ExpensiveInterfaceExample.java @@ -35,4 +35,18 @@ public interface ExpensiveInterfaceExample { @Expensive public void m5(); + interface I2 extends I { + @PerformanceCritical void m3(); + } + + + abstract class ImplementsInterface implements I2 { + + @Expensive void expensive() {} + + @Override public void m1() { + expensive(); + } + } + } diff --git a/infer/tests/codetoanalyze/java/checkers/issues.exp b/infer/tests/codetoanalyze/java/checkers/issues.exp index adc5e1354..03108c2d2 100644 --- a/infer/tests/codetoanalyze/java/checkers/issues.exp +++ b/infer/tests/codetoanalyze/java/checkers/issues.exp @@ -20,6 +20,7 @@ codetoanalyze/java/checkers/ExpensiveCallExample.java, void PerformanceCriticalS codetoanalyze/java/checkers/ExpensiveInheritanceExample.java, void ExpensiveInheritanceExample.doesReportBecauseTypeFlowInsensitive(A), 2, CHECKERS_CALLS_EXPENSIVE_METHOD, [] codetoanalyze/java/checkers/ExpensiveInheritanceExample.java, void ExpensiveInheritanceExample.reportsAssumingObjectOfTypeA(), 2, CHECKERS_CALLS_EXPENSIVE_METHOD, [] codetoanalyze/java/checkers/ExpensiveInheritanceExample.java, void ExpensiveInheritanceExample.reportsBecauseFooIsExpensiveInA(A), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, [] +codetoanalyze/java/checkers/ExpensiveInterfaceExample.java, void ExpensiveInterfaceExample$ImplementsInterface.m1(), 1, CHECKERS_CALLS_EXPENSIVE_METHOD, [] codetoanalyze/java/checkers/ExpensiveSubtypingExample.java, void ExpensiveSubtypingExample.m3(), 0, CHECKERS_EXPENSIVE_OVERRIDES_UNANNOTATED, [return from a call to void ExpensiveSubtypingExample.m4()] codetoanalyze/java/checkers/FragmentRetainsViewExample.java, void FragmentRetainsViewExample.onDestroyView(), 0, CHECKERS_FRAGMENT_RETAINS_VIEW, [return from a call to void FragmentRetainsViewExample.onDestroyView()] codetoanalyze/java/checkers/FragmentRetainsViewExample.java, void FragmentRetainsViewExample.onDestroyView(), 0, CHECKERS_FRAGMENT_RETAINS_VIEW, [return from a call to void FragmentRetainsViewExample.onDestroyView()]