revive --pmd-xml

Summary:
Turns out it was useful, so it is now reborn in OCaml.

Fixes https://github.com/facebook/infer/issues/1262.

Reviewed By: skcho

Differential Revision: D22016185

fbshipit-source-id: 31ccb7540
master
Jules Villard 5 years ago committed by Facebook GitHub Bot
parent 7221c93980
commit 97feb81c3b

@ -41,6 +41,7 @@ BUILD_SYSTEMS_TESTS += \
linters \ linters \
project_root_rel \ project_root_rel \
reactive \ reactive \
results_xml \
run_hidden_linters \ run_hidden_linters \
tracebugs \ tracebugs \
utf8_in_procname \ utf8_in_procname \

@ -829,6 +829,10 @@ OPTIONS
DEPRECATED: Specify the file containing perf profiler data to read DEPRECATED: Specify the file containing perf profiler data to read
See also infer-analyze(1). See also infer-analyze(1).
--pmd-xml
Activates: Output issues in (PMD) XML format in
infer-out/report.xml (Conversely: --no-pmd-xml) See also infer-run(1).
--print-active-checkers --print-active-checkers
Activates: Print the active checkers before starting the analysis Activates: Print the active checkers before starting the analysis
(Conversely: --no-print-active-checkers) See also infer-analyze(1). (Conversely: --no-print-active-checkers) See also infer-analyze(1).

@ -88,6 +88,10 @@ OPTIONS
Show this manual with all internal options in the INTERNAL OPTIONS Show this manual with all internal options in the INTERNAL OPTIONS
section section
--pmd-xml
Activates: Output issues in (PMD) XML format in
infer-out/report.xml (Conversely: --no-pmd-xml)
--print-logs --print-logs
Activates: Also log messages to stdout and stderr (Conversely: Activates: Also log messages to stdout and stderr (Conversely:
--no-print-logs) --no-print-logs)

@ -829,6 +829,10 @@ OPTIONS
DEPRECATED: Specify the file containing perf profiler data to read DEPRECATED: Specify the file containing perf profiler data to read
See also infer-analyze(1). See also infer-analyze(1).
--pmd-xml
Activates: Output issues in (PMD) XML format in
infer-out/report.xml (Conversely: --no-pmd-xml) See also infer-run(1).
--print-active-checkers --print-active-checkers
Activates: Print the active checkers before starting the analysis Activates: Print the active checkers before starting the analysis
(Conversely: --no-print-active-checkers) See also infer-analyze(1). (Conversely: --no-print-active-checkers) See also infer-analyze(1).

@ -1705,6 +1705,12 @@ and patterns_skip_translation =
"Matcher or list of matchers for names of files that should not be analyzed at all." ) "Matcher or list of matchers for names of files that should not be analyzed at all." )
and pmd_xml =
CLOpt.mk_bool ~long:"pmd-xml"
~in_help:InferCommand.[(Run, manual_generic)]
"Output issues in (PMD) XML format in infer-out/report.xml"
and print_active_checkers = and print_active_checkers =
CLOpt.mk_bool ~long:"print-active-checkers" CLOpt.mk_bool ~long:"print-active-checkers"
~in_help:InferCommand.[(Analyze, manual_generic)] ~in_help:InferCommand.[(Analyze, manual_generic)]
@ -2927,6 +2933,8 @@ and patterns_skip_implementation = match patterns_skip_implementation with k, r
and patterns_skip_translation = match patterns_skip_translation with k, r -> (k, !r) and patterns_skip_translation = match patterns_skip_translation with k, r -> (k, !r)
and pmd_xml = !pmd_xml
and print_active_checkers = !print_active_checkers and print_active_checkers = !print_active_checkers
and print_builtins = !print_builtins and print_builtins = !print_builtins

@ -417,6 +417,8 @@ val only_cheap_debug : bool
val only_footprint : bool val only_footprint : bool
val pmd_xml : bool
val print_active_checkers : bool val print_active_checkers : bool
val print_builtins : bool val print_builtins : bool

@ -29,6 +29,7 @@ type id =
| ReportHtml | ReportHtml
| ReportJson | ReportJson
| ReportText | ReportText
| ReportXML
| RetainCycles | RetainCycles
| RunState | RunState
| Specs | Specs
@ -147,6 +148,11 @@ let of_id = function
; kind= File ; kind= File
; before_incremental_analysis= Delete ; before_incremental_analysis= Delete
; before_caching_capture= Delete } ; before_caching_capture= Delete }
| ReportXML ->
{ rel_path= "report.xml"
; kind= File
; before_incremental_analysis= Delete
; before_caching_capture= Delete }
| RetainCycles -> | RetainCycles ->
{ rel_path= "retain_cycle_dotty" { rel_path= "retain_cycle_dotty"
; kind= Directory ; kind= Directory

@ -30,6 +30,7 @@ type id =
| ReportHtml (** directory of the HTML report *) | ReportHtml (** directory of the HTML report *)
| ReportJson (** the main product of the analysis: [report.json] *) | ReportJson (** the main product of the analysis: [report.json] *)
| ReportText (** a human-readable textual version of [report.json] *) | ReportText (** a human-readable textual version of [report.json] *)
| ReportXML (** a PMD-style XML version of [report.json] *)
| RetainCycles (** directory of retain cycles dotty files *) | RetainCycles (** directory of retain cycles dotty files *)
| RunState (** internal data about the last infer run *) | RunState (** internal data about the last infer run *)
| Specs (** directory containing summaries as .specs files *) | Specs (** directory containing summaries as .specs files *)

@ -198,7 +198,9 @@ let report ?(suppress_console = false) () =
TextReport.create_from_json TextReport.create_from_json
~quiet:(Config.quiet || suppress_console) ~quiet:(Config.quiet || suppress_console)
~console_limit:Config.report_console_limit ~report_txt:(ResultsDir.get_path ReportText) ~console_limit:Config.report_console_limit ~report_txt:(ResultsDir.get_path ReportText)
~report_json:issues_json ) ; ~report_json:issues_json ;
if Config.pmd_xml then
XMLReport.write ~xml_path:(ResultsDir.get_path ReportXML) ~json_path:issues_json ) ;
if Config.(test_determinator && process_clang_ast) then if Config.(test_determinator && process_clang_ast) then
TestDeterminator.merge_test_determinator_results () ; TestDeterminator.merge_test_determinator_results () ;
() ()

@ -19,6 +19,10 @@ let basename_checker_prefix = "checker-"
let basename_of_checker {Checker.id} = basename_checker_prefix ^ id let basename_of_checker {Checker.id} = basename_checker_prefix ^ id
let url_fragment_of_issue_type unique_id =
Printf.sprintf "%s#%s" all_issues_basename (String.lowercase unique_id)
let get_checker_web_documentation (checker : Checker.config) = let get_checker_web_documentation (checker : Checker.config) =
match checker.kind with match checker.kind with
| UserFacing {title; markdown_body} -> | UserFacing {title; markdown_body} ->
@ -268,7 +272,7 @@ let pp_checker_issue_types f checker =
Checker.equal issue_checker checker ) Checker.equal issue_checker checker )
in in
let pp_issue f {IssueType.unique_id} = let pp_issue f {IssueType.unique_id} =
F.fprintf f "- [%s](%s.md#%s)@\n" unique_id all_issues_basename (String.lowercase unique_id) F.fprintf f "- [%s](%s)@\n" unique_id (url_fragment_of_issue_type unique_id)
in in
List.iter checker_issues ~f:(pp_issue f) List.iter checker_issues ~f:(pp_issue f)

@ -21,3 +21,7 @@ val show_issue_types : IssueType.t list -> unit
val write_website : website_root:string -> unit val write_website : website_root:string -> unit
(** generate files for the fbinfer.com website *) (** generate files for the fbinfer.com website *)
val url_fragment_of_issue_type : string -> string
(** given an issue type unique ID, return the URL fragment relative to the website documentation,
e.g. [url_fragment_of_issue_type "NULL_DEREFERENCE"] is ["all-issue-types#null_dereference"] *)

@ -0,0 +1,53 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
module F = Format
let pp_current_date_and_time f =
let {Unix.tm_year; tm_mon; tm_mday; tm_hour; tm_min; tm_sec} = Unix.time () |> Unix.localtime in
F.fprintf f "%d-%02d-%dT%d:%d:%d.000000" (1900 + tm_year) tm_mon tm_mday tm_hour tm_min tm_sec
let pp_xml_issue f (issue : Jsonbug_t.jsonbug) =
let java_class_name, java_package, method_name =
let java_result =
let open IOption.Let_syntax in
if String.is_suffix ~suffix:".java" issue.file then
let* package_class_method, _formals_types = String.lsplit2 ~on:'(' issue.procedure in
let* package_class, method_ = String.rsplit2 ~on:'.' package_class_method in
let+ package, class_ = String.rsplit2 ~on:'.' package_class in
(package, class_, method_)
else None
in
match java_result with None -> ("", "", issue.procedure) | Some result -> result
in
F.fprintf f
{|<file name="%s">
<violation begincolumn="%d" beginline="%d" endcolumn="%d" endline="%d" class="%s" method="%s" package="%s" priority="1" rule="%s" ruleset="Infer Rules" externalinfourl="https://fbinfer.com/docs/next/%s">%s</violation>
</file>|}
issue.file (max issue.column 0) issue.line (max issue.column 0) (issue.line + 1) java_class_name
method_name java_package issue.bug_type
(Help.url_fragment_of_issue_type issue.bug_type)
issue.qualifier
let is_user_visible (issue : Jsonbug_t.jsonbug) =
Option.is_none issue.censored_reason && not (String.equal issue.severity "INFO")
let pp_xml_issue_filter f issue = if is_user_visible issue then pp_xml_issue f issue
let write ~xml_path ~json_path =
let report = Atdgen_runtime.Util.Json.from_file Jsonbug_j.read_report json_path in
Utils.with_file_out xml_path ~f:(fun out_channel ->
let f = F.formatter_of_out_channel out_channel in
F.fprintf f {|@[%cpmd version="5.4.1" date="%t">
%a
</pmd>@.|} '<' pp_current_date_and_time
(Pp.seq ~sep:"\n" pp_xml_issue_filter)
report )

@ -0,0 +1,11 @@
(*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*)
open! IStd
val write : xml_path:string -> json_path:string -> unit
(** read the JSON report at [json_path] and translates it to a PMD-style XML report in [xml_path] *)

@ -0,0 +1,20 @@
# Copyright (c) Facebook, Inc. and its affiliates.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
TESTS_DIR = ../..
CODETOANALYZE_DIR = ../codetoanalyze
CLANG_OPTIONS = -c
INFER_OPTIONS = --project-root $(CODETOANALYZE_DIR) --pmd-xml
INFERPRINT_OPTIONS = --issues-tests
SOURCES = $(CODETOANALYZE_DIR)/hello.c
include $(TESTS_DIR)/clang.make
issues.exp.test: infer-out/report.json
# massage the first line of the XML to delete non-reproducible information (the current date)
$(QUIET)sed -e 's/date="[^"]*"/date=""/' infer-out/report.xml > $@

@ -0,0 +1,5 @@
<pmd version="5.4.1" date="">
<file name="hello.c">
<violation begincolumn="3" beginline="12" endcolumn="3" endline="13" class="" method="test" package="" priority="1" rule="NULL_DEREFERENCE" ruleset="Infer Rules" externalinfourl="https://fbinfer.com/docs/next/all-issue-types#null_dereference">pointer `s` last assigned on line 11 could be null and is dereferenced at line 12, column 3.</violation>
</file>
</pmd>
Loading…
Cancel
Save