diff --git a/infer/annotations/com/facebook/infer/annotprocess/ClassToSourceMapper.java b/infer/annotations/com/facebook/infer/annotprocess/ClassToSourceMapper.java index 8e28dd997..e0256c8e1 100644 --- a/infer/annotations/com/facebook/infer/annotprocess/ClassToSourceMapper.java +++ b/infer/annotations/com/facebook/infer/annotprocess/ClassToSourceMapper.java @@ -16,9 +16,7 @@ import com.sun.source.util.TreePath; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; -import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import java.util.Set; @@ -29,7 +27,6 @@ import javax.annotation.processing.SupportedOptions; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; @SupportedOptions({ "classSourceMapOutputFilename" }) // this says: "process all classes, even ones without any annotations" diff --git a/infer/annotations/com/facebook/infer/annotprocess/CollectSuppressWarnings.java b/infer/annotations/com/facebook/infer/annotprocess/CollectSuppressWarnings.java index 6c531526f..8e303c0db 100644 --- a/infer/annotations/com/facebook/infer/annotprocess/CollectSuppressWarnings.java +++ b/infer/annotations/com/facebook/infer/annotprocess/CollectSuppressWarnings.java @@ -9,11 +9,9 @@ package com.facebook.infer.annotprocess; -import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; import java.util.Collections; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; @@ -22,39 +20,37 @@ import java.util.Set; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedOptions; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; +@SupportedOptions({ "SuppressWarningsOutputFilename" }) @SupportedAnnotationTypes({ "java.lang.SuppressWarnings" }) public class CollectSuppressWarnings extends AbstractProcessor { - private static final String ANNOTATION_ENV_VAR = "INFER_ANNOTATIONS_OUT"; + private static final String OUTPUT_FILENAME_OPTION = "SuppressWarningsOutputFilename"; - private String mOutputFilename; - - // map of (classes -> methods in class). an empty set means suppress all - // warnings on class + // map of (classes -> methods in class). an empty set means suppress all warnings on class public Map> mSuppressMap = new LinkedHashMap>(); // total number of classes/methods with a SuppressWarnings annotation private int mNumToSuppress = 0; // write the methods/classes to suppress to .inferconfig-style JSON - private void exportSuppressMap() throws FileNotFoundException, IOException { - Map env = System.getenv(); - if (env.get(ANNOTATION_ENV_VAR) == null) { - throw new RuntimeException("Env variable INFER_ANNOTATIONS_OUT not set"); - } else { - mOutputFilename = env.get(ANNOTATION_ENV_VAR); - } + private void exportSuppressMap() throws IOException { + + Map options = processingEnv.getOptions(); + String mOutputFilename = + Preconditions.checkNotNull(options.get(OUTPUT_FILENAME_OPTION), + "The filename should be passed from the Infer top-level script"); // output .inferconfig format file in JSON try (PrintWriter out = new PrintWriter(mOutputFilename)) { int elemCount = 0; - out.println("{ \"suppress_procedures\": ["); + out.println("{ \"suppress_warnings\": ["); for (Map.Entry> entry : mSuppressMap.entrySet()) { String clazz = entry.getKey(); Set methods = entry.getValue(); @@ -79,10 +75,11 @@ public class CollectSuppressWarnings extends AbstractProcessor { } // collect all of the SuppressWarnings annotations from the Java source files being compiled - public boolean process(Set annotations, RoundEnvironment env) { + public boolean process(Set annotations, RoundEnvironment roundEnv) { + Elements elements = processingEnv.getElementUtils(); for (TypeElement te : annotations) { - for (Element e : env.getElementsAnnotatedWith(te)) { + for (Element e : roundEnv.getElementsAnnotatedWith(te)) { SuppressWarnings annot = e.getAnnotation(SuppressWarnings.class); if (annot != null && shouldProcess(annot)) { if (e instanceof TypeElement) { // class @@ -107,13 +104,14 @@ public class CollectSuppressWarnings extends AbstractProcessor { } } - if (env.processingOver() && mNumToSuppress > 0) { + if (roundEnv.processingOver() && mNumToSuppress > 0) { try { exportSuppressMap(); } catch (IOException e) { throw new RuntimeException(e); } } + return false; } diff --git a/infer/annotations/com/facebook/infer/annotprocess/Preconditions.java b/infer/annotations/com/facebook/infer/annotprocess/Preconditions.java new file mode 100644 index 000000000..98a3d1e35 --- /dev/null +++ b/infer/annotations/com/facebook/infer/annotprocess/Preconditions.java @@ -0,0 +1,21 @@ +/* + * 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.annotprocess; + +public class Preconditions { + + public static T checkNotNull(T reference, String errorMessage) { + if (reference == null) { + throw new NullPointerException(errorMessage); + } + return reference; + } + +} diff --git a/infer/lib/python/inferlib/config.py b/infer/lib/python/inferlib/config.py index 03cc25ca5..e2a285d99 100644 --- a/infer/lib/python/inferlib/config.py +++ b/infer/lib/python/inferlib/config.py @@ -53,6 +53,7 @@ LOG_FILE = 'toplevel.log' BUCK_INFER_OUT = 'infer' CLASS_SOURCE_MAP_OUTPUT_FILENAME_OPTION = 'classSourceMapOutputFilename' +SUPRESS_WARNINGS_OUTPUT_FILENAME_OPTION = 'SuppressWarningsOutputFilename' # exit value when infer finds something to report diff --git a/infer/lib/python/inferlib/jwlib.py b/infer/lib/python/inferlib/jwlib.py index 74daff9fb..7c34ccc02 100644 --- a/infer/lib/python/inferlib/jwlib.py +++ b/infer/lib/python/inferlib/jwlib.py @@ -80,7 +80,6 @@ class CompilerCall(object): self.original_arguments = arguments self.args, self.remaining_args = parser.parse_known_args(arguments) self.verbose_out = None - self.annotations_out = None def run(self): if self.args.version: @@ -136,7 +135,10 @@ class CompilerCall(object): suffix='.out', prefix='annotations_', delete=False) as annot_out: - self.annotations_out = annot_out.name + self.suppress_warnings_out = annot_out.name + javac_cmd += ['-A%s=%s' % + (config.SUPRESS_WARNINGS_OUTPUT_FILENAME_OPTION, + self.suppress_warnings_out)] with tempfile.NamedTemporaryFile( mode='w', @@ -144,7 +146,6 @@ class CompilerCall(object): prefix='javac_', delete=False) as file_out: self.verbose_out = file_out.name - os.environ['INFER_ANNOTATIONS_OUT'] = self.annotations_out try: subprocess.check_call(javac_cmd, stderr=file_out) except subprocess.CalledProcessError: @@ -241,14 +242,12 @@ class AnalyzerWithFrontendWrapper(analyze.AnalyzerWrapper): infer_cmd += [ '-results_dir', self.args.infer_out, '-verbose_out', self.javac.verbose_out, + '-suppress_warnings_out', self.javac.suppress_warnings_out, ] if os.path.isfile(config.MODELS_JAR): infer_cmd += ['-models', config.MODELS_JAR] - if self.javac.annotations_out is not None: - infer_cmd += ['-local_config', self.javac.annotations_out] - infer_cmd.append('-no-static_final') if self.args.debug: @@ -276,4 +275,4 @@ class AnalyzerWithFrontendWrapper(analyze.AnalyzerWrapper): def _close(self): os.remove(self.javac.verbose_out) - os.remove(self.javac.annotations_out) + os.remove(self.javac.suppress_warnings_out) diff --git a/infer/src/backend/inferconfig.ml b/infer/src/backend/inferconfig.ml index fb98cb43e..bbef92071 100644 --- a/infer/src/backend/inferconfig.ml +++ b/infer/src/backend/inferconfig.ml @@ -12,7 +12,7 @@ let inferconfig_file = ".inferconfig" let inferconfig_home = ref None -let local_config = ref None +let suppress_warnings_annotations = ref None (** Look up a key in a json file containing a list of strings *) let lookup_string_list key json = @@ -280,8 +280,8 @@ module NeverReturnNull = FileOrProcMatcher(struct let json_key = "never_returning_null" end) -module ProcMatcher = FileOrProcMatcher(struct - let json_key = "suppress_procedures" +module SuppressWarningsMatcher = FileOrProcMatcher(struct + let json_key = "suppress_warnings" end) module SkipTranslationMatcher = FileOrProcMatcher(struct diff --git a/infer/src/backend/inferconfig.mli b/infer/src/backend/inferconfig.mli index 76691e92e..cdd787336 100644 --- a/infer/src/backend/inferconfig.mli +++ b/infer/src/backend/inferconfig.mli @@ -9,7 +9,7 @@ val inferconfig_home : string option ref -val local_config : string option ref +val suppress_warnings_annotations : string option ref (** get the path to the .inferconfig file *) val inferconfig : unit -> string @@ -45,7 +45,7 @@ module NeverReturnNull : Matcher module SkipTranslationMatcher : Matcher -module ProcMatcher : Matcher +module SuppressWarningsMatcher : Matcher (** Load the config file and list the files to report on *) val test: unit -> unit diff --git a/infer/src/backend/reporting.ml b/infer/src/backend/reporting.ml index 1bef1d7a2..368912d46 100644 --- a/infer/src/backend/reporting.ml +++ b/infer/src/backend/reporting.ml @@ -55,12 +55,11 @@ let log_issue ?(pre = None) exn = let should_suppress_warnings summary = - if !Config.curr_language = Config.C_CPP then false - else - let annotated_signature = - Annotations.get_annotated_signature summary.Specs.attributes in - let ret_annotation, _ = annotated_signature.Annotations.ret in - Annotations.ia_is_suppress_warnings ret_annotation in + !Config.curr_language = Config.Java && + let annotated_signature = + Annotations.get_annotated_signature summary.Specs.attributes in + let ret_annotation, _ = annotated_signature.Annotations.ret in + Annotations.ia_is_suppress_warnings ret_annotation in match Specs.get_summary proc_name with | Some summary when should_suppress_warnings summary -> () | Some summary -> diff --git a/infer/src/java/jAnnotation.ml b/infer/src/java/jAnnotation.ml index b94f3a6ba..e17edc3fe 100644 --- a/infer/src/java/jAnnotation.ml +++ b/infer/src/java/jAnnotation.ml @@ -17,10 +17,10 @@ let suppress_warnings_lookup = ref None let load_suppress_warnings_lookup () = let default_matcher = fun _ -> false in let matcher = - match !Inferconfig.local_config with + match !Inferconfig.suppress_warnings_annotations with | Some f -> (try - let m = Inferconfig.ProcMatcher.load_matcher f in + let m = Inferconfig.SuppressWarningsMatcher.load_matcher f in (m DB.source_file_empty) with Yojson.Json_error _ -> default_matcher) diff --git a/infer/src/java/jMain.ml b/infer/src/java/jMain.ml index d4f2c883e..f710a41ed 100644 --- a/infer/src/java/jMain.ml +++ b/infer/src/java/jMain.ml @@ -62,10 +62,10 @@ let arg_desc = None, "Set the path to the javac verbose output" ; - "-local_config", - Arg.String (fun s -> Inferconfig.local_config := Some s), + "-suppress_warnings_out", + Arg.String (fun s -> Inferconfig.suppress_warnings_annotations := Some s), Some "Path", - "Path to local config file" + "Path to list of collected @SuppressWarnings annotations" ; ] in Arg.create_options_desc false "Parsing Options" desc