Summary: public This is an initial version of the Expensive checker which only report violations on direct calls. The main objective is to setup all the files for this new checker. The next steps are: 1) run the checker in interprocedural mode 2) Save in the summary of a method foo() the annotation attribute Expensive if a direct callee of foo is annotated with Expensive 3) Check that Expensive is enforced by subtyping, i.e. check that non-expensive method cannot be overwritten by a method annotated with Expensive Reviewed By: cristianoc Differential Revision: D2629947 fb-gh-sync-id: 0e06f85master
parent
f88164dae9
commit
f5ddb983fe
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.infer.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface Expensive {}
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.infer.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface PerformanceCritical {}
|
@ -0,0 +1,61 @@
|
||||
(*
|
||||
* Copyright (c) 2015 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*)
|
||||
|
||||
module L = Logging
|
||||
|
||||
|
||||
let calls_expensive_method = "CHECKERS_CALLS_EXPENSIVE_METHOD"
|
||||
|
||||
|
||||
let search_expensive_call checked_pnames expensive_callee (pname, _) =
|
||||
match expensive_callee with
|
||||
| Some callee_pname -> Some callee_pname
|
||||
| None ->
|
||||
if Procname.Set.mem pname !checked_pnames then None
|
||||
else
|
||||
begin
|
||||
checked_pnames := Procname.Set.add pname !checked_pnames;
|
||||
match AttributesTable.load_attributes pname with
|
||||
| None -> None
|
||||
| Some attributes ->
|
||||
let annotated_signature = Annotations.get_annotated_signature attributes in
|
||||
let ret_annotation, _ = annotated_signature.Annotations.ret in
|
||||
if Annotations.ia_is_expensive ret_annotation then
|
||||
Some pname
|
||||
else
|
||||
None
|
||||
end
|
||||
|
||||
|
||||
let is_performance_critical attributes =
|
||||
let annotated_signature = Annotations.get_annotated_signature attributes in
|
||||
let ret_annotation, _ = annotated_signature.Annotations.ret in
|
||||
Annotations.ia_is_performance_critical ret_annotation
|
||||
|
||||
|
||||
let callback_performance_checker _ _ _ tenv pname pdesc : unit =
|
||||
let attributes = Cfg.Procdesc.get_attributes pdesc in
|
||||
let expensive_call_found =
|
||||
let checked_pnames = ref Procname.Set.empty in
|
||||
Cfg.Procdesc.fold_calls
|
||||
(search_expensive_call checked_pnames)
|
||||
None
|
||||
pdesc in
|
||||
match expensive_call_found with
|
||||
| None -> ()
|
||||
| Some callee_pname when is_performance_critical attributes ->
|
||||
let description =
|
||||
Printf.sprintf "Method %s annotated with @%s calls method %s annotated with @%s"
|
||||
(Procname.to_simplified_string pname)
|
||||
Annotations.performance_critical
|
||||
(Procname.to_string callee_pname)
|
||||
Annotations.expensive in
|
||||
Checkers.ST.report_error
|
||||
pname pdesc calls_expensive_method (Cfg.Procdesc.get_loc pdesc) description
|
||||
| Some _ -> ()
|
@ -0,0 +1,11 @@
|
||||
(*
|
||||
* Copyright (c) 2015 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*)
|
||||
|
||||
|
||||
val callback_performance_checker : Callbacks.proc_callback_t
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2013 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package codetoanalyze.java.checkers;
|
||||
|
||||
import com.facebook.infer.annotation.Expensive;
|
||||
import com.facebook.infer.annotation.PerformanceCritical;
|
||||
|
||||
public class ExpensiveCallExample {
|
||||
|
||||
Object mObject;
|
||||
|
||||
@Expensive
|
||||
void expensiveMethod() {
|
||||
mObject = new Object();
|
||||
}
|
||||
|
||||
@PerformanceCritical
|
||||
void shouldReportExpensiveCallWarning() {
|
||||
expensiveMethod();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - present Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package endtoend.java.checkers;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static utils.matchers.ResultContainsExactly.containsExactly;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import utils.InferException;
|
||||
import utils.InferResults;
|
||||
|
||||
public class ExpensiveCallTest {
|
||||
|
||||
public static final String SOURCE_FILE =
|
||||
"infer/tests/codetoanalyze/java/checkers/ExpensiveCallExample.java";
|
||||
|
||||
public static final String CALLS_EXPENSIVE_METHOD = "CHECKERS_CALLS_EXPENSIVE_METHOD";
|
||||
|
||||
private static InferResults inferResults;
|
||||
|
||||
@BeforeClass
|
||||
public static void loadResults() throws InterruptedException, IOException {
|
||||
inferResults =
|
||||
InferResults.loadCheckersResults(ImmutableCastTest.class, SOURCE_FILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchErrors()
|
||||
throws IOException, InterruptedException, InferException {
|
||||
String[] methods = {
|
||||
"shouldReportExpensiveCallWarning",
|
||||
};
|
||||
assertThat(
|
||||
"Results should contain " + CALLS_EXPENSIVE_METHOD,
|
||||
inferResults,
|
||||
containsExactly(
|
||||
CALLS_EXPENSIVE_METHOD,
|
||||
SOURCE_FILE,
|
||||
methods));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in new issue