diff options
-rw-r--r-- | lib/dialyzer/doc/manual.txt | 6 | ||||
-rw-r--r-- | lib/dialyzer/doc/src/dialyzer.xml | 6 | ||||
-rw-r--r-- | lib/dialyzer/src/Makefile | 5 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer.erl | 15 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_cl_parse.erl | 19 | ||||
-rw-r--r-- | lib/dialyzer/src/dialyzer_gui.erl | 1381 | ||||
-rw-r--r-- | lib/hipe/tools/Makefile | 3 | ||||
-rw-r--r-- | lib/hipe/tools/hipe_tool.erl | 525 |
8 files changed, 18 insertions, 1942 deletions
diff --git a/lib/dialyzer/doc/manual.txt b/lib/dialyzer/doc/manual.txt index d519ac960b..29c9518d84 100644 --- a/lib/dialyzer/doc/manual.txt +++ b/lib/dialyzer/doc/manual.txt @@ -125,7 +125,7 @@ The exit status of the command line version is: Usage: dialyzer [--help] [--version] [--shell] [--quiet] [--verbose] [-pa dir]* [--plt plt] [--plts plt*] [-Ddefine]* [-I include_dir]* [--output_plt file] [-Wwarn]* - [--src] [--gui | --wx] [files_or_dirs] [-r dirs] + [--src] [--gui] [files_or_dirs] [-r dirs] [--apps applications] [-o outfile] [--build_plt] [--add_to_plt] [--remove_from_plt] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] @@ -234,9 +234,7 @@ Options: --fullpath Display the full path names of files for which warnings are emitted. --gui - Use the gs-based GUI. - --wx - Use the wx-based GUI. + Use the GUI. Note: * denotes that multiple occurrences of these options are possible. diff --git a/lib/dialyzer/doc/src/dialyzer.xml b/lib/dialyzer/doc/src/dialyzer.xml index 5bac999ac8..2a631c3010 100644 --- a/lib/dialyzer/doc/src/dialyzer.xml +++ b/lib/dialyzer/doc/src/dialyzer.xml @@ -67,7 +67,7 @@ dialyzer [--help] [--version] [--shell] [--quiet] [--verbose] [-pa dir]* [--plt plt] [--plts plt*] [-Ddefine]* [-I include_dir]* [--output_plt file] [-Wwarn]* - [--src] [--gui | --wx] [files_or_dirs] [-r dirs] + [--src] [--gui] [files_or_dirs] [-r dirs] [--apps applications] [-o outfile] [--build_plt] [--add_to_plt] [--remove_from_plt] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] @@ -204,9 +204,7 @@ <tag><c><![CDATA[--fullpath]]></c></tag> <item>Display the full path names of files for which warnings are emitted.</item> <tag><c><![CDATA[--gui]]></c></tag> - <item>Use the gs-based GUI.</item> - <tag><c><![CDATA[--wx]]></c></tag> - <item>Use the wx-based GUI.</item> + <item>Use the GUI.</item> </taglist> <note> <p>* denotes that multiple occurrences of these options are possible.</p> diff --git a/lib/dialyzer/src/Makefile b/lib/dialyzer/src/Makefile index bb2edd419a..d7265ba31a 100644 --- a/lib/dialyzer/src/Makefile +++ b/lib/dialyzer/src/Makefile @@ -57,7 +57,6 @@ MODULES = \ dialyzer_dataflow \ dialyzer_dep \ dialyzer_explanation \ - dialyzer_gui \ dialyzer_gui_wx \ dialyzer_options \ dialyzer_plt \ @@ -113,9 +112,6 @@ $(EBIN)/dialyzer_cl_parse.$(EMULATOR): dialyzer_cl_parse.erl ../vsn.mk $(EBIN)/dialyzer_plt.$(EMULATOR): dialyzer_plt.erl ../vsn.mk $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_plt.erl -$(EBIN)/dialyzer_gui.$(EMULATOR): dialyzer_gui.erl ../vsn.mk - $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_gui.erl - $(EBIN)/dialyzer_gui_wx.$(EMULATOR): dialyzer_gui_wx.erl ../vsn.mk $(erlc_verbose)erlc -W $(ERL_COMPILE_FLAGS) -DVSN="\"v$(VSN)\"" -o$(EBIN) dialyzer_gui_wx.erl @@ -140,7 +136,6 @@ $(EBIN)/dialyzer_contracts.beam: dialyzer.hrl $(EBIN)/dialyzer_dataflow.beam: dialyzer.hrl $(EBIN)/dialyzer_dep.beam: dialyzer.hrl $(EBIN)/dialyzer_explanation.beam: dialyzer.hrl -$(EBIN)/dialyzer_gui.beam: dialyzer.hrl $(EBIN)/dialyzer_gui_wx.beam: dialyzer.hrl dialyzer_gui_wx.hrl $(EBIN)/dialyzer_options.beam: dialyzer.hrl $(EBIN)/dialyzer_plt.beam: dialyzer.hrl diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 822aa0826a..35156afff2 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -62,18 +62,18 @@ plain_cl() -> cl_halt(cl_check_init(Opts), Opts); {plt_info, Opts} -> cl_halt(cl_print_plt_info(Opts), Opts); - {{gui, Type}, Opts} -> + {gui, Opts} -> try check_gui_options(Opts) catch throw:{dialyzer_error, Msg} -> cl_error(Msg) end, case Opts#options.check_plt of true -> case cl_check_init(Opts#options{get_warnings = false}) of - {ok, _} -> gui_halt(internal_gui(Type, Opts), Opts); + {ok, _} -> gui_halt(internal_gui(Opts), Opts); {error, _} = Error -> cl_halt(Error, Opts) end; false -> - gui_halt(internal_gui(Type, Opts), Opts) + gui_halt(internal_gui(Opts), Opts) end; {cl, Opts} -> case Opts#options.check_plt of @@ -179,12 +179,9 @@ run(Opts) -> erlang:error({dialyzer_error, lists:flatten(ErrorMsg)}) end. -internal_gui(Type, OptsRecord) -> +internal_gui(OptsRecord) -> F = fun() -> - case Type of - gs -> dialyzer_gui:start(OptsRecord); - wx -> dialyzer_gui_wx:start(OptsRecord) - end, + dialyzer_gui_wx:start(OptsRecord), ?RET_NOTHING_SUSPICIOUS end, doit(F). @@ -205,7 +202,7 @@ gui(Opts) -> case cl_check_init(OptsRecord) of {ok, ?RET_NOTHING_SUSPICIOUS} -> F = fun() -> - dialyzer_gui:start(OptsRecord) + dialyzer_gui_wx:start(OptsRecord) end, case doit(F) of {ok, _} -> ok; diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl index 2ea3d3af5a..db27b2037d 100644 --- a/lib/dialyzer/src/dialyzer_cl_parse.erl +++ b/lib/dialyzer/src/dialyzer_cl_parse.erl @@ -2,7 +2,7 @@ %%----------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2012. All Rights Reserved. +%% Copyright Ericsson AB 2006-2013. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,7 +30,7 @@ -type dial_cl_parse_ret() :: {'check_init', #options{}} | {'plt_info', #options{}} | {'cl', #options{}} - | {{'gui', 'gs' | 'wx'}, #options{}} + | {'gui', #options{}} | {'error', string()}. -type deep_string() :: string() | [deep_string()]. @@ -193,12 +193,9 @@ cl(["--dump_callgraph", File|T]) -> put(dialyzer_callgraph_file, File), cl(T); cl(["--gui"|T]) -> - put(dialyzer_options_mode, {gui, gs}), + put(dialyzer_options_mode, gui), cl(T); -cl(["--wx"|T]) -> - put(dialyzer_options_mode, {gui, wx}), - cl(T); -cl(["--solver",Solver|T]) -> % not documented +cl(["--solver", Solver|T]) -> % not documented append_var(dialyzer_solvers, [list_to_atom(Solver)]), cl(T); cl([H|_] = L) -> @@ -217,7 +214,7 @@ cl([]) -> {plt_info, cl_options()}; false -> case get(dialyzer_options_mode) of - {gui, _} = GUI -> {GUI, common_options()}; + gui -> {gui, common_options()}; cl -> case get(dialyzer_options_analysis_type) =:= plt_check of true -> {check_init, cl_options()}; @@ -361,7 +358,7 @@ help_message() -> S = "Usage: dialyzer [--help] [--version] [--shell] [--quiet] [--verbose] [-pa dir]* [--plt plt] [--plts plt*] [-Ddefine]* [-I include_dir]* [--output_plt file] [-Wwarn]* - [--src] [--gui | --wx] [files_or_dirs] [-r dirs] + [--src] [--gui] [files_or_dirs] [-r dirs] [--apps applications] [-o outfile] [--build_plt] [--add_to_plt] [--remove_from_plt] [--check_plt] [--no_check_plt] [--plt_info] [--get_warnings] @@ -473,9 +470,7 @@ Options: --fullpath Display the full path names of files for which warnings are emitted. --gui - Use the gs-based GUI. - --wx - Use the wx-based GUI. + Use the GUI. Note: * denotes that multiple occurrences of these options are possible. diff --git a/lib/dialyzer/src/dialyzer_gui.erl b/lib/dialyzer/src/dialyzer_gui.erl deleted file mode 100644 index 97e5752577..0000000000 --- a/lib/dialyzer/src/dialyzer_gui.erl +++ /dev/null @@ -1,1381 +0,0 @@ -%% -*- erlang-indent-level: 2 -*- -%%------------------------------------------------------------------------ -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2006-2013. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% - -%%%----------------------------------------------------------------------- -%%% File : dialyzer_gui.erl -%%% Authors : Tobias Lindahl <[email protected]> -%%% Kostis Sagonas <[email protected]> -%%% Description : The graphical user interface for the Dialyzer tool. -%%% -%%% Created : 27 Apr 2004 by Tobias Lindahl <[email protected]> -%%%----------------------------------------------------------------------- - --module(dialyzer_gui). --compile([{nowarn_deprecated_function,{gs,button,2}}, - {nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,destroy,1}}, - {nowarn_deprecated_function,{gs,editor,2}}, - {nowarn_deprecated_function,{gs,entry,2}}, - {nowarn_deprecated_function,{gs,frame,2}}, - {nowarn_deprecated_function,{gs,label,2}}, - {nowarn_deprecated_function,{gs,listbox,2}}, - {nowarn_deprecated_function,{gs,menu,2}}, - {nowarn_deprecated_function,{gs,menubar,2}}, - {nowarn_deprecated_function,{gs,menubutton,2}}, - {nowarn_deprecated_function,{gs,menuitem,2}}, - {nowarn_deprecated_function,{gs,radiobutton,2}}, - {nowarn_deprecated_function,{gs,read,2}}, - {nowarn_deprecated_function,{gs,start,0}}, - {nowarn_deprecated_function,{gs,stop,0}}, - {nowarn_deprecated_function,{gs,window,2}}]). - --export([start/1]). - --include("dialyzer.hrl"). - -%%------------------------------------------------------------------------ - --define(DIALYZER_ERROR_TITLE, "Dialyzer Error"). --define(DIALYZER_MESSAGE_TITLE, "Dialyzer Message"). - -%%------------------------------------------------------------------------ - --type gs_object() :: any(). %% XXX: should be imported from gs - --record(mode, {start_byte_code :: gs_object(), - start_src_code :: gs_object()}). - --record(menu, {file_save_log :: gs_object(), - file_save_warn :: gs_object(), - file_quit :: gs_object(), - help_about :: gs_object(), - help_manual :: gs_object(), - help_warnings :: gs_object(), - opts_macros :: gs_object(), - opts_includes :: gs_object(), - plt_empty :: gs_object(), - plt_search_doc :: gs_object(), - plt_show_doc :: gs_object(), - warnings :: gs_object()}). - --record(gui_state, {add_all :: gs_object(), - add_file :: gs_object(), - add_rec :: gs_object(), - chosen_box :: gs_object(), - analysis_pid :: pid(), - del_file :: gs_object(), - doc_plt :: dialyzer_plt:plt(), - clear_chosen :: gs_object(), - clear_log :: gs_object(), - clear_warn :: gs_object(), - init_plt :: dialyzer_plt:plt(), - dir_entry :: gs_object(), - file_box :: gs_object(), - file_wd :: gs_object(), - gs :: gs_object(), - log :: gs_object(), - menu :: #menu{}, - mode :: #mode{}, - options :: #options{}, - packer :: gs_object(), - run :: gs_object(), - stop :: gs_object(), - top :: gs_object(), - warnings_box :: gs_object(), - backend_pid :: pid()}). - -%%------------------------------------------------------------------------ - --spec start(#options{}) -> ?RET_NOTHING_SUSPICIOUS. - -start(#options{from = From, init_plts = InitPltFiles, - legal_warnings = LegalWarnings} = DialyzerOptions) -> - process_flag(trap_exit, true), - - GS = gs:start(), - code:add_pathsa(["."]), - WH = [{width, 1000}, {height, 550}], - EmptySpace = {stretch, 1}, - - {ok, Host} = inet:gethostname(), - %% --------- Top Window -------------- - TopWin = gs:window(GS, [{title, "Dialyzer " ++ ?VSN ++ " @ " ++ Host}, - {configure, true}, - {default, listbox, {bg, white}}, - {default, editor, {bg, white}}, - {default, entry, {bg, white}}, - {default, button, {font, {helvetica, bold, 12}}}, - {default, label, {font, {helvetica, bold, 12}}} - |WH]), - Packer = gs:frame(TopWin, [{packer_x, [{stretch, 3},{fixed, 200}, - {stretch, 7}]}, - {packer_y, [{fixed, 25}, {fixed, 20}, - {stretch, 1, 50}, - {fixed, 25}, {fixed, 20}, - {stretch, 1, 50}, - {fixed, 25}]}]), - - %% --------- Chosen box -------------- - gs:label(Packer, [{label, {text, "Directories or modules to analyze"}}, - {height, 20}, {pack_xy, {1, 2}}]), - ChosenBox = gs:listbox(Packer, [{pack_xy, {1, 3}}, {vscroll, right}, - {selectmode, multiple}]), - - %% --------- File box -------------- - gs:label(Packer, [{label, {text, "File"}}, {height, 20}, {pack_xy, {1,5}}]), - FilePacker = gs:frame(Packer, [{packer_x, [{fixed, 30}, {stretch, 1, 100}]}, - {packer_y, [{fixed, 25}, {stretch, 1, 25}]}, - {pack_xy, {1, 6}}]), - gs:label(FilePacker, [{label, {text, "Dir:"}}, {pack_xy, {1, 1}}]), - DirEntry = gs:entry(FilePacker, [{height, 30}, {pack_xy, {2, 1}}, - {keypress, true}]), - File = gs:listbox(FilePacker, [{pack_x, {1,2}}, {pack_y, 2}, - {selectmode, multiple}, {doubleclick, true}, - {vscroll, right}]), - - %% --------- Options -------------- - gs:label(Packer, [{label, {text, "Analysis Options"}}, - {height, 20}, {pack_xy, {2, 2}}]), - ModePacker = gs:frame(Packer, [{packer_x, [{fixed, 75}, {fixed, 120}]}, - {packer_y, [{fixed, 20}, {fixed, 20}, - {fixed, 20}, - %% EmptySpace, - {fixed, 20}, {fixed, 20}, - {fixed, 20}, EmptySpace]}, - {bw, 10}, {relief, flat}, - {default, {radiobutton, {align, w}}}, - {default, {label, {align, w}}}, - {pack_xy, {2, 3}}]), - - %% Bytecode vs. Source code - gs:label(ModePacker, [{label, {text, "File Type:"}}, - {height, 20}, {pack_xy, {1,1}}]), - {ByteSel, SrcSel} = case From of - byte_code -> {[{select, true}], []}; - src_code -> {[], [{select, true}]} - end, - ModeByteCode = gs:radiobutton(ModePacker, - ByteSel ++ [{group, start_from}, - {label, {text,"BeamFiles"}}, - {pack_xy, {2,1}}]), - ModeSrcCode = gs:radiobutton(ModePacker, - SrcSel ++ [{group, start_from}, - {label, {text,"SourceFiles"}}, - {pack_xy, {2,2}}]), - Mode = #mode{start_byte_code = ModeByteCode, - start_src_code = ModeSrcCode}, - - %% --------- Log box -------------- - gs:label(Packer, [{label, {text, "Log"}}, {height, 20}, {pack_xy, {3,2}}]), - Log = gs:editor(Packer, [{pack_x, 3}, {pack_y, 3}, {enable, false}, - {font, {courier, 12}}, {vscroll, right}, - {wrap, word}]), - - %% --------- Warnings box -------------- - gs:label(Packer, [{label, {text, "Warnings"}},{height, 20},{pack_xy, {3,5}}]), - WarningsBox = gs:editor(Packer, [{pack_x, {2,3}}, {pack_y, 6}, - {enable, false}, - {font, {courier, 12}}, {vscroll, right}, - {wrap, word}]), - - %% --------- Buttons -------------- - ButtonPackerHighLeft = - gs:frame(Packer, [{packer_x, [{fixed, 50}, {fixed, 65}, EmptySpace]}, - {pack_xy, {1,4}}]), - ButtonPackerHighRight = - gs:frame(Packer, [{packer_x, [{fixed, 70}, {fixed, 70}, EmptySpace]}, - {pack_xy, {3,4}}]), - ButtonPackerLowLeft = - gs:frame(Packer, [{packer_x, [{fixed, 50}, - {fixed, 60}, - {fixed, 110}, - EmptySpace]}, - {pack_xy, {1,7}}]), - ButtonPackerLowRight = - gs:frame(Packer, [{packer_x, [{fixed, 100}, - {fixed, 70}, - EmptySpace, - {fixed, 70}, - {fixed, 70}]}, - {pack_x, {2,3}}, {pack_y, 7}]), - - WHButton = [{width, 60}, {height, 20}], - AddFile = gs:button(ButtonPackerLowLeft, [{pack_xy, {1, 1}}, - {label, {text,"Add"}}|WHButton]), - AddAll = gs:button(ButtonPackerLowLeft, [{pack_xy, {2, 1}}, - {label, {text,"Add All"}}|WHButton]), - AddRec = gs:button(ButtonPackerLowLeft, [{pack_xy, {3, 1}}, - {label, {text,"Add Recursively"}} - |WHButton]), - DelFile = gs:button(ButtonPackerHighLeft, [{pack_xy, {1, 1}}, - {label, {text,"Delete"}}|WHButton]), - ClearChosen = gs:button(ButtonPackerHighLeft, [{pack_xy, {2, 1}}, - {label, {text,"Delete All"}} - |WHButton]), - ClearLog = gs:button(ButtonPackerHighRight, [{pack_xy, {1, 1}}, - {label, {text,"Clear Log"}} - |WHButton]), - ClearWarn = gs:button(ButtonPackerLowRight, [{pack_xy, {1, 1}}, - {label, {text,"Clear Warnings"}} - |WHButton]), - - Run = gs:button(ButtonPackerLowRight, [{pack_xy, {4, 1}}, - {label, {text,"Run"}}|WHButton]), - Stop = gs:button(ButtonPackerLowRight, [{pack_xy, {5, 1}}, {enable, false}, - {label, {text,"Stop"}}|WHButton]), - - %% --------- Menu -------------- - MenuBar = gs:menubar(TopWin, []), - - %% File Menu - MenuBarFile = gs:menubutton(MenuBar, [{label, {text, "File"}}]), - MenuFile = gs:menu(MenuBarFile, []), - MenuFileSaveWarn = gs:menuitem(MenuFile, [{label, {text, "Save Warnings"}}]), - MenuFileSaveLog = gs:menuitem(MenuFile, [{label, {text, "Save Log"}}]), - MenuFileQuit = gs:menuitem(MenuFile, [{label, {text, "Quit"}}]), - - %% Warnings Menu - MenuBarWarn = gs:menubutton(MenuBar, [{label, {text, "Warnings"}}]), - MenuWarn = gs:menu(MenuBarWarn, []), - MenuWarnMatch = gs:menuitem(MenuWarn, [{label, {text, "Match failures"}}, - {itemtype, check}, {select, true}]), - MenuWarnFailingCall = gs:menuitem(MenuWarn, - [{label, {text, "Failing function calls"}}, - {itemtype, check}, {select, true}]), - MenuWarnFunApp = gs:menuitem(MenuWarn, [{label, - {text, "Bad fun applications"}}, - {itemtype, check}, {select, true}]), - MenuWarnOpaque = gs:menuitem(MenuWarn, [{label, - {text, "Opaqueness violations"}}, - {itemtype, check}, {select, true}]), - MenuWarnLists = gs:menuitem(MenuWarn, - [{label, {text, "Improper list constructions"}}, - {itemtype, check}, {select, true}]), - MenuWarnNotCalled = gs:menuitem(MenuWarn, - [{label, {text, "Unused functions"}}, - {itemtype, check}, {select, true}]), - MenuWarnReturnOnlyExit = gs:menuitem(MenuWarn, - [{label, - {text, "Error handling functions"}}, - {itemtype, check}, {select, false}]), - MenuWarnReturnNoReturn = gs:menuitem(MenuWarn, - [{label, - {text, "Functions of no return"}}, - {itemtype, check}, {select, true}]), - MenuWarnCallNonExported = gs:menuitem(MenuWarn, - [{label, - {text, "Call to unexported function"}}, - {itemtype, check}, {select, true}]), - MenuWarnRaceCondition = gs:menuitem(MenuWarn, - [{label, - {text,"Possible race conditions"}}, - {itemtype, check}, {select, false}]), - MenuWarnContractTypes = gs:menuitem(MenuWarn, - [{label, {text, "Wrong contracts"}}, - {itemtype, check}, {select, true}]), - MenuWarnContractSyntax = gs:menuitem(MenuWarn, - [{label, - {text, "Wrong contract syntax"}}, - {itemtype, check}, {select, true}]), - - %% PLT Menu - MenuBarPLT = gs:menubutton(MenuBar, [{label, {text,"PLT"}}]), - MenuPLT = gs:menu(MenuBarPLT, []), - MenuPLTEmpty = gs:menuitem(MenuPLT, [{label, {text, "Init with empty PLT"}}, - {itemtype, check}, {select, false}]), - MenuPLTShow = gs:menuitem(MenuPLT, [{label, {text, "Show contents"}}]), - MenuPLTSearch = gs:menuitem(MenuPLT, [{label, {text, "Search contents"}}]), - - %% Options Menu - MenuBarOpts = gs:menubutton(MenuBar, [{label,{text,"Options"}}]), - MenuOpts = gs:menu(MenuBarOpts, []), - MenuOptsMacros = gs:menuitem(MenuOpts, - [{label, {text, "Manage Macro Definitions"}}]), - MenuOptsIncludes = gs:menuitem(MenuOpts, - [{label, {text, "Manage Include Directories"}}]), - - %% Help - MenuBarHelp = gs:menubutton(MenuBar, [{label, {text, "Help"}}, {side, right}]), - MenuHelp = gs:menu(MenuBarHelp, []), - MenuHelpManual = gs:menuitem(MenuHelp, [{label, {text, "Manual"}}]), - MenuHelpWarnings = gs:menuitem(MenuHelp, [{label, {text, "Warning Options"}}]), - MenuHelpAbout = gs:menuitem(MenuHelp, [{label, {text, "About"}}]), - - Warnings = [{?WARN_RETURN_NO_RETURN, MenuWarnReturnNoReturn}, - {?WARN_RETURN_ONLY_EXIT, MenuWarnReturnOnlyExit}, - {?WARN_NOT_CALLED, MenuWarnNotCalled}, - {?WARN_NON_PROPER_LIST, MenuWarnLists}, - {?WARN_FUN_APP, MenuWarnFunApp}, - {?WARN_MATCHING, MenuWarnMatch}, - {?WARN_OPAQUE, MenuWarnOpaque}, - {?WARN_FAILING_CALL, MenuWarnFailingCall}, - {?WARN_CALLGRAPH, MenuWarnCallNonExported}, - {?WARN_RACE_CONDITION, MenuWarnRaceCondition}, - %% For contracts. - {?WARN_CONTRACT_TYPES, MenuWarnContractTypes}, - {?WARN_CONTRACT_SYNTAX, MenuWarnContractSyntax} - ], - - init_warnings(Warnings, LegalWarnings), - - Menu = #menu{file_quit = MenuFileQuit, - plt_empty = MenuPLTEmpty, - help_manual = MenuHelpManual, - help_about = MenuHelpAbout, - help_warnings = MenuHelpWarnings, - opts_macros = MenuOptsMacros, - opts_includes = MenuOptsIncludes, - plt_search_doc = MenuPLTSearch, - plt_show_doc = MenuPLTShow, - file_save_log = MenuFileSaveLog, - file_save_warn = MenuFileSaveWarn, - warnings = Warnings}, - - %% --------- Init -------------- - gs:config(TopWin, [{map, true}]), - gs:config(Packer, WH), - {ok, CWD} = file:get_cwd(), - - InitPlt = - case InitPltFiles of - [] -> dialyzer_plt:new(); - _ -> - Plts = [dialyzer_plt:from_file(F) || F <- InitPltFiles], - dialyzer_plt:merge_plts_or_report_conflicts(InitPltFiles, Plts) - end, - - State = #gui_state{add_all = AddAll, - add_file = AddFile, - add_rec = AddRec, - chosen_box = ChosenBox, - clear_chosen = ClearChosen, - clear_log = ClearLog, - clear_warn = ClearWarn, - del_file = DelFile, - doc_plt = dialyzer_plt:new(), - dir_entry = DirEntry, - file_box = File, - file_wd = CWD, - gs = GS, - init_plt = InitPlt, - log = Log, - menu = Menu, - mode = Mode, - options = DialyzerOptions, - packer = Packer, - run = Run, - stop = Stop, - top = TopWin, - warnings_box = WarningsBox}, - NewState = change_dir_or_add_file(State, "."), - gui_loop(NewState). - -%% ---------------------------------------------------------------- -%% -%% Main GUI Loop -%% - --spec gui_loop(#gui_state{}) -> ?RET_NOTHING_SUSPICIOUS. - -gui_loop(#gui_state{add_all = AddAll, add_file = AddFile, add_rec = AddRec, - backend_pid = BackendPid, chosen_box = ChosenBox, - clear_chosen = ClearChosen, clear_log = ClearLog, - clear_warn = ClearWarn, del_file = DelFile, - dir_entry = DirEntry, file_box = File, log = Log, - menu = Menu, packer = Packer, run = Run, stop = Stop, - top = TopWin, warnings_box = Warn} = State) -> - %% --- Menu --- - Quit = Menu#menu.file_quit, - Manual = Menu#menu.help_manual, - Warnings = Menu#menu.help_warnings, - About = Menu#menu.help_about, - SaveLog = Menu#menu.file_save_log, - SaveWarn = Menu#menu.file_save_warn, - SearchPlt = Menu#menu.plt_search_doc, - ShowPlt = Menu#menu.plt_show_doc, - Macros = Menu#menu.opts_macros, - Includes = Menu#menu.opts_includes, - - receive - {gs, TopWin, configure, _Data, [W, H|_]} -> - gs:config(Packer, [{width, W}, {height, H}]), - gui_loop(State); - {gs, TopWin, destroy, _Data, _Args} -> - ?RET_NOTHING_SUSPICIOUS; - {gs, File, doubleclick, _, [_Id, Text|_]} -> - NewState = change_dir_or_add_file(State, Text), - gui_loop(NewState); - {gs, DirEntry, keypress, _, ['Return'|_]} -> - gs:config(TopWin, [{setfocus, true}]), - NewState = change_dir_absolute(State, gs:read(DirEntry, text)), - gui_loop(NewState); - {gs, DirEntry, keypress, _, _} -> - gui_loop(State); - %% ----- Buttons ----- - {gs, AddFile, click, _, _} -> - handle_add_files(State), - gui_loop(State); - {gs, AddAll, click, _, _} -> - handle_add_all_click(State), - gui_loop(State); - {gs, AddRec, click, _, _} -> - handle_add_rec_click(State), - gui_loop(State); - {gs, DelFile, click, _, _} -> - handle_file_delete(State), - gui_loop(State); - {gs, ClearChosen, click, _, _} -> - gs:config(ChosenBox, [clear]), - gui_loop(State); - {gs, ClearLog, click, _, _} -> - Log = State#gui_state.log, - gs:config(Log, [{enable, true}]), - gs:config(Log, [clear]), - gs:config(Log, [{enable, false}]), - gui_loop(State); - {gs, ClearWarn, click, _, _} -> - Warn = State#gui_state.warnings_box, - gs:config(Warn, [{enable, true}]), - gs:config(Warn, [clear]), - gs:config(Warn, [{enable, false}]), - gui_loop(State); - {gs, Run, click, _, _} -> - NewState = start_analysis(State), - gui_loop(NewState); - {gs, Stop, click, _, _} -> - config_gui_stop(State), - BackendPid ! {self(), stop}, - update_editor(Log, "\n***** Analysis stopped ****\n"), - gui_loop(State); - %% ----- Menu ----- - {gs, Quit, click, _, _} -> - case maybe_quit(State) of - true -> ?RET_NOTHING_SUSPICIOUS; - false -> gui_loop(State) - end; - {gs, Manual, click, _, _} -> - spawn_link(fun() -> manual(State) end), - gui_loop(State); - {gs, Warnings, click, _, _} -> - spawn_link(fun() -> warnings(State) end), - gui_loop(State); - {gs, About, click, _, _} -> - spawn_link(fun() -> about(State) end), - gui_loop(State); - {gs, SaveLog, click, _, _} -> - save_log(State), - gui_loop(State); - {gs, SaveWarn, click, _, _} -> - save_warn(State), - gui_loop(State); - {gs, SearchPlt, click, _, _} -> - spawn_link(fun() -> search_doc_plt(State) end), - gui_loop(State); - {gs, ShowPlt, click, _, _} -> - spawn_link(fun() -> show_doc_plt(State) end), - gui_loop(State); - {gs, Macros, click, _, _} -> - Self = self(), - spawn_link(fun() -> macro_dialog(State, Self) end), - gui_loop(State); - {gs, Includes, click, _, _} -> - Self = self(), - spawn_link(fun() -> include_dialog(State, Self) end), - gui_loop(State); - {new_options, NewOptions} -> - NewState = State#gui_state{options = NewOptions}, - gui_loop(NewState); - %% ----- Analysis ----- - {BackendPid, ext_calls, ExtCalls} -> - Msg = io_lib:format("The following functions are called " - "but type information about them is not available.\n" - "The analysis might get more precise by including " - "the modules containing these functions:\n\n\t~p\n", - [ExtCalls]), - free_editor(State, "Analysis done", Msg), - gui_loop(State); - {BackendPid, ext_types, ExtTypes} -> - Map = fun({M,F,A}) -> io_lib:format("~p:~p/~p",[M,F,A]) end, - ExtTypeString = string:join(lists:map(Map, ExtTypes), "\n"), - Msg = io_lib:format("The following remote types are being used " - "but information about them is not available.\n" - "The analysis might get more precise by including " - "the modules containing these types and making sure " - "that they are exported:\n~s\n", [ExtTypeString]), - free_editor(State, "Analysis done", Msg), - gui_loop(State); - {BackendPid, log, LogMsg} -> - update_editor(Log, LogMsg), - gui_loop(State); - {BackendPid, warnings, Warns} -> - SortedWarns = lists:keysort(2, Warns), %% Sort on file/line - WarnList = [dialyzer:format_warning(W) || W <- SortedWarns], - update_editor(Warn, lists:flatten(WarnList)), - gui_loop(State); - {BackendPid, done, _NewPlt, NewDocPlt} -> - message(State, "Analysis done"), - config_gui_stop(State), - gui_loop(State#gui_state{doc_plt = NewDocPlt}); - {'EXIT', BackendPid, {error, Reason}} -> - free_editor(State, ?DIALYZER_ERROR_TITLE, Reason), - config_gui_stop(State), - gui_loop(State); - {'EXIT', BackendPid, Reason} when Reason =/= 'normal' -> - free_editor(State, ?DIALYZER_ERROR_TITLE, io_lib:format("~p", [Reason])), - config_gui_stop(State), - gui_loop(State); - _Other -> - %% io:format("Received ~p\n", [Other]), - gui_loop(State) - end. - -%% ---------------------------------------------------------------- -%% -%% Main window actions -%% - -%% ---- Adding and deleting files ---- - -handle_add_all_click(#gui_state{chosen_box = ChosenBox, file_box = File, - file_wd = FWD, mode = Mode}) -> - case gs:read(File, items) of - [] -> - ok; - Add0 -> - gs:config(File, [{selection, clear}]), - Add1 = ordsets:subtract(Add0, [".."]), - Add = ordsets:from_list([filename:join(FWD, X) || X <- Add1]), - case gs:read(Mode#mode.start_byte_code, select) of - true -> - add_files(filter_mods(Add, ".beam"), ChosenBox, byte_code); - false -> - add_files(filter_mods(Add, ".erl"), ChosenBox, src_code) - end - end. - -all_subdirs(Dirs) -> - all_subdirs(Dirs, []). - -all_subdirs([Dir|T], Acc) -> - {ok, Files} = file:list_dir(Dir), - SubDirs = lists:zf(fun(F) -> - SubDir = filename:join(Dir, F), - case filelib:is_dir(SubDir) of - true -> {true, SubDir}; - false -> false - end - end, Files), - NewAcc = ordsets:union(ordsets:from_list(SubDirs), Acc), - all_subdirs(T ++ SubDirs, NewAcc); -all_subdirs([], Acc) -> - Acc. - -handle_add_rec_click(#gui_state{chosen_box = ChosenBox, file_box = File, - file_wd = FWD, mode = Mode}) -> - case gs:read(File, selection) of - [] -> - ok; - List -> - gs:config(File, [{selection, clear}]), - Dirs1 = [gs:read(File, {get, X}) || X <- List], - Dirs2 = ordsets:from_list([filename:join(FWD, X) || X <- Dirs1]), - Dirs3 = ordsets:filter(fun(X) -> filelib:is_dir(X) end, Dirs2), - TargetDirs = ordsets:union(Dirs3, all_subdirs(Dirs3)), - {Code, Ext} = case gs:read(Mode#mode.start_byte_code, select) of - true -> {byte_code, ".beam"}; - false -> {src_code, ".erl"} - end, - add_files(filter_mods(TargetDirs, Ext), ChosenBox, Code) - end. - -handle_add_files(#gui_state{chosen_box = ChosenBox, file_box = File, - file_wd = FWD, mode = Mode}) -> - case gs:read(File, selection) of - [] -> - ok; - List -> - gs:config(File, [{selection, clear}]), - Add0 = [gs:read(File, {get, X}) || X <- List], - Add = ordsets:from_list([filename:join(FWD, X) || X <- Add0]), - case gs:read(Mode#mode.start_byte_code, select) of - true -> - add_files(filter_mods(Add, ".beam"), ChosenBox, byte_code); - false -> - add_files(filter_mods(Add, ".erl"), ChosenBox, src_code) - end - end. - -filter_mods(Mods, Extension) -> - Fun = fun(X) -> - filename:extension(X) =:= Extension - orelse - (filelib:is_dir(X) andalso - contains_files(X, Extension)) - end, - ordsets:filter(Fun, Mods). - -contains_files(Dir, Extension) -> - {ok, Files} = file:list_dir(Dir), - lists:any(fun(X) -> filename:extension(X) =:= Extension end, Files). - -add_files(Add, ChosenBox, Type) -> - Set = gs:read(ChosenBox, items), - Set1 = - case Type of - byte_code -> filter_mods(Set, ".beam"); - src_code -> filter_mods(Set, ".erl") - end, - Files = ordsets:union(Add, Set1), - gs:config(ChosenBox, [{items, Files}]), - ok. - -handle_file_delete(#gui_state{chosen_box = ChosenBox}) -> - List = gs:read(ChosenBox, selection), - lists:foreach(fun(X) -> gs:config(ChosenBox, [{del, X}]) end, - lists:reverse(lists:sort(List))). - -%% ---- Other ---- - -change_dir_or_add_file(#gui_state{file_wd = FWD, mode = Mode, dir_entry = Dir, - chosen_box = CBox, file_box = File} = State, - Text) -> - NewWDorFile = - case Text of - ".." -> filename:join(butlast(filename:split(FWD))); - "." -> FWD; - _ -> filename:join(FWD, Text) - end, - case filelib:is_dir(NewWDorFile) of - true -> - gs:config(Dir, [{text, NewWDorFile}]), - {ok, List} = file:list_dir(NewWDorFile), - gs:config(File, [{items, [".."|lists:sort(List)]}]), - State#gui_state{file_wd = NewWDorFile}; - false -> - case gs:read(Mode#mode.start_byte_code, select) of - true -> - case filter_mods([NewWDorFile], ".beam") of - [] -> ok; - RealFiles -> add_files(RealFiles, CBox, byte_code) - end; - false -> - case filter_mods([NewWDorFile], ".erl") of - [] -> ok; - RealFiles -> add_files(RealFiles, CBox, src_code) - end - end, - State - end. - -butlast([H1, H2 | T]) -> - [H1 | butlast([H2|T])]; -butlast([_]) -> - []; -butlast([]) -> - ["/"]. - -change_dir_absolute(#gui_state{file_wd = FWD, dir_entry = Dir, - file_box = File} = State, - Text) -> - case filelib:is_dir(Text) of - true -> - WD = filename:join(FWD, Text), - gs:config(Dir, [{text, WD}]), - {ok, List} = file:list_dir(WD), - gs:config(File, [{items, [".."|lists:sort(List)]}]), - State#gui_state{file_wd = WD}; - false -> - State - end. - -init_warnings([{Tag, GSItem}|Left], LegalWarnings) -> - Select = ordsets:is_element(Tag, LegalWarnings), - gs:config(GSItem, [{select, Select}]), - init_warnings(Left, LegalWarnings); -init_warnings([], _LegalWarnings) -> - ok. - -config_gui_start(State) -> - Enabled = [{enable, true}], - Disabled = [{enable, false}], - gs:config(State#gui_state.stop, Enabled), - gs:config(State#gui_state.run, Disabled), - gs:config(State#gui_state.del_file, Disabled), - gs:config(State#gui_state.clear_chosen, Disabled), - gs:config(State#gui_state.add_file, Disabled), - gs:config(State#gui_state.add_all, Disabled), - gs:config(State#gui_state.add_rec, Disabled), - gs:config(State#gui_state.clear_warn, Disabled), - gs:config(State#gui_state.clear_log, Disabled), - Menu = State#gui_state.menu, - gs:config(Menu#menu.file_save_warn, Disabled), - gs:config(Menu#menu.file_save_log, Disabled), - gs:config(Menu#menu.opts_macros, Disabled), - gs:config(Menu#menu.opts_includes, Disabled), - gs:config(Menu#menu.plt_empty, Disabled), - gs:config(Menu#menu.plt_search_doc, Disabled), - gs:config(Menu#menu.plt_show_doc, Disabled), - Mode = State#gui_state.mode, - gs:config(Mode#mode.start_byte_code, Disabled), - gs:config(Mode#mode.start_src_code, Disabled). - -config_gui_stop(State) -> - Enabled = [{enable, true}], - Disabled = [{enable, false}], - gs:config(State#gui_state.stop, Disabled), - gs:config(State#gui_state.run, Enabled), - gs:config(State#gui_state.del_file, Enabled), - gs:config(State#gui_state.clear_chosen, Enabled), - gs:config(State#gui_state.add_file, Enabled), - gs:config(State#gui_state.add_all, Enabled), - gs:config(State#gui_state.add_rec, Enabled), - gs:config(State#gui_state.clear_warn, Enabled), - gs:config(State#gui_state.clear_log, Enabled), - Menu = State#gui_state.menu, - gs:config(Menu#menu.file_save_warn, Enabled), - gs:config(Menu#menu.file_save_log, Enabled), - gs:config(Menu#menu.opts_macros, Enabled), - gs:config(Menu#menu.opts_includes, Enabled), - gs:config(Menu#menu.plt_empty, Enabled), - gs:config(Menu#menu.plt_search_doc, Enabled), - gs:config(Menu#menu.plt_show_doc, Enabled), - Mode = State#gui_state.mode, - gs:config(Mode#mode.start_byte_code, Enabled), - gs:config(Mode#mode.start_src_code, Enabled). - -%% ---------------------------------------------------------------- -%% -%% Messages -%% - -message(State, Message) -> - output_sms(State, ?DIALYZER_MESSAGE_TITLE, Message). - -error_sms(State, Message) -> - output_sms(State, ?DIALYZER_ERROR_TITLE, Message). - -%% -%% This function is to be used *only* for small messages because lines -%% are not wrapped and the created window has a limited area for text. -%% For bigger messages, the function free_editor/3 is to be used. -%% -output_sms(#gui_state{gs = GS, top = TopWin}, Title, Message) -> - %% Lines = string:words(Message, $\n), - %% io:format("The message has ~w lines\n", [Lines]), - WH = [{width, 400}, {height, 100}], - MessageWin = gs:window(GS, [{title, Title}, - {default, button, {font, {helvetica, bold, 12}}} - |WH]), - MessagePacker = gs:frame(MessageWin, [{packer_y, [{fixed, 75}, {fixed, 25}]}, - {packer_x, [{fixed, 175},{fixed, 50}, - {fixed, 175}]}]), - gs:label(MessagePacker, [{pack_x, {1, 3}}, {pack_y, 1}, - {label, {text, Message}}]), - OK = gs:button(MessagePacker, [{label, {text, "OK"}}, {pack_xy, {2, 2}}]), - gs:config(MessageWin, [{map, true}]), - gs:config(MessagePacker, WH), - message_loop(OK, MessageWin, TopWin). - -message_loop(Ok, Win, TopWin) -> - receive - {gs, Ok, click, _, _} -> - gs:destroy(Win); - {gs, Win, destroy, _, _} -> - ok; - {gs, TopWin, destroy, _, _} -> - exit(normal); - {gs, _, _, _, _} -> - message_loop(Ok, Win, TopWin) - end. - -dialog(#gui_state{gs = GS, top = TopWin}, Message, OkLabel, CancelLabel) -> - WH = [{width, 400}, {height, 100}], - WHButton = [{width, 70}, {height, 20}], - DialogWin = gs:window(GS, [{title, "Dialyzer Message"}, - {default, button, {font, {helvetica, bold, 12}}} - |WH]), - DialogPacker = gs:frame(DialogWin, [{packer_y, [{fixed, 75}, {fixed, 25}]}, - {packer_x, [{fixed, 150}, {fixed, 50}, - {fixed, 50}, {fixed, 150}]}]), - gs:label(DialogPacker, [{pack_x, {1,4}}, {pack_y, 1}, - {label, {text, Message}}]), - Ok = gs:button(DialogPacker, [{label, {text, OkLabel}}, - {pack_xy, {2,2}}|WHButton]), - Cancel = gs:button(DialogPacker, [{label, {text, CancelLabel}}, - {pack_xy, {3,2}}|WHButton]), - gs:config(DialogWin, [{map, true}]), - gs:config(DialogPacker, WH), - dialog_loop(Ok, Cancel, DialogWin, TopWin). - -dialog_loop(Ok, Cancel, Win, TopWin) -> - receive - {gs, Ok, click, _, _} -> - gs:destroy(Win), - true; - {gs, Cancel, click, _, _} -> - gs:destroy(Win), - false; - {gs, Win, destroy, _, _} -> - false; - {gs, TopWin, destroy, _, _} -> - exit(normal); - {gs, _, _, _, _} -> - dialog_loop(Ok, Cancel, Win, TopWin) - end. - -maybe_quit(#gui_state{top = TopWin} = State) -> - case dialog(State, "Do you really want to quit?", "Yes", "No") of - true -> - flush(), - gs:destroy(TopWin), - gs:stop(), - true; - false -> - false - end. - - -%% ---------------------------------------------------------------- -%% -%% Menu actions -%% - -%% ---- Help Menu ---- - -manual(State) -> - help_menu_common(State, "Dialyzer Manual", 500, "manual.txt", white). - -warnings(State) -> - help_menu_common(State, "Dialyzer Warnings", 500, "warnings.txt", white). - -about(State) -> - help_menu_common(State, "About Dialyzer", 160, "about.txt", yellow). - -help_menu_common(#gui_state{gs = GS, top = TopWin} = State, - Title, Height, TxtFileName, BackGroundColor) -> - WH = [{width, 600}, {height, Height}], - Win = gs:window(GS, [{title, Title}, {configure, true}, - {default, editor, {bg, BackGroundColor}} | WH]), - EmptySpace = {stretch, 1}, - Frame = gs:frame(Win, [{packer_x, [EmptySpace, {fixed, 60}, EmptySpace]}, - {packer_y, [EmptySpace, {fixed, 30}]} | WH]), - Editor = gs:editor(Frame, [{pack_x, {1, 3}}, {pack_y, 1}, - {font, {courier, 12}}, {vscroll, right}, - {wrap, word}]), - Button = gs:button(Frame, [{label, {text, "Ok"}}, {pack_xy, {2, 2}}]), - gs:config(Win, [{map, true}]), - gs:config(Frame, WH), - AboutFile = filename:join([code:lib_dir(dialyzer), "doc", TxtFileName]), - case gs:config(Editor, {load, AboutFile}) of - {error, Reason} -> - gs:destroy(Win), - error_sms(State, - io_lib:format("Could not find doc/~s file!\n\n ~p", - [TxtFileName, Reason])); - ok -> - gs:config(Editor, [{enable, false}]), - show_info_loop(TopWin, Win, Frame, Button) - end. - -%% ---- File Menu ---- - -save_log(#gui_state{file_wd = CWD, log = Log} = State) -> - {Win, Entry, OkButton, CancelButton} = file_box(State, "Save Log", CWD), - save_loop(State, OkButton, CancelButton, Entry, Win, Log). - -save_warn(#gui_state{file_wd = CWD, warnings_box = WBox} = State) -> - {Win, Entry, OkButton, CancelButton} = file_box(State, "Save Warnings", CWD), - save_loop(State, OkButton, CancelButton, Entry, Win, WBox). - -file_box(#gui_state{gs = GS}, Title, Default) -> - WH = [{width, 400}, {height, 75}], - Win = gs:window(GS, [{title, Title}|WH]), - Fix25 = {fixed, 27}, Fix75 = {fixed, 75}, - WinPacker = gs:frame(Win, [{packer_y, [Fix25, Fix25, Fix25]}, - {packer_x, [Fix75, Fix75, Fix75, {fixed, 175}]}]), - gs:label(WinPacker, [{pack_xy, {1,2}}, {label, {text, "Enter file:"}}]), - Entry = gs:entry(WinPacker, [{pack_x, {2,4}}, {pack_y, 2}, {keypress, true}]), - OkButton = gs:button(WinPacker, [{label, {text, "Ok"}}, {pack_xy, {2,3}}]), - CancelButton = gs:button(WinPacker, [{label, {text, "Cancel"}}, - {pack_xy, {3,3}}]), - gs:config(Entry, [{text, Default}]), - gs:config(Win, [{map, true}]), - gs:config(WinPacker, WH), - {Win, Entry, OkButton, CancelButton}. - -save_loop(#gui_state{top = TopWin} = State, - OkButton, CancelButton, Entry, Save, Editor) -> - receive - {gs, OkButton, click, _, _} -> - File = gs:read(Entry, text), - case gs:config(Editor, [{save, File}]) of - {error, _} -> - error_sms(State, "Could not write to file:\n" ++ File), - save_loop(State, OkButton, CancelButton, Entry, Save, Editor); - _ -> - gs:destroy(Save) - end; - {gs, Entry, keypress, _, ['Return'|_]} -> - File = gs:read(Entry, text), - case gs:config(Editor, [{save, File}]) of - {error, _} -> - error_sms(State, "Could not write to file:\n" ++ File), - save_loop(State, OkButton, CancelButton, Entry, Save, Editor); - _ -> - gs:destroy(Save) - end; - {gs, Entry, keypress, _, _} -> - save_loop(State, OkButton, CancelButton, Entry, Save, Editor); - {gs, CancelButton, click, _, _} -> - gs:destroy(Save); - {gs, TopWin, destroy, _, _} -> - exit(normal); - {gs, Save, destroy, _, _} -> - ok; - {gs, _, _, _, _} -> - save_loop(State, OkButton, CancelButton, Entry, Save, Editor) - end. - -%% ---- Plt Menu ---- - -search_doc_plt(#gui_state{gs = GS, top = TopWin} = State) -> - WH = [{width, 400}, {height, 100}], - WHB = [{width, 120}, {height, 30}], - Title = io_lib:format("Search the PLT", []), - Win = gs:window(GS, [{title, Title}, {configure, true}, - {default, editor, {bg, white}} | WH]), - EmptySpace = {stretch, 1}, - Frame = gs:frame(Win, [{packer_x, [EmptySpace, EmptySpace, EmptySpace]}, - {packer_y, [{fixed, 30}, {fixed, 30}, - EmptySpace, {fixed, 30}]} | WH]), - gs:label(Frame, [{pack_xy, {1,1}}, {label, {text, "Module"}}]), - ModEntry = gs:entry(Frame, [{pack_xy, {1,2}}]), - gs:label(Frame, [{pack_xy, {2,1}}, {label, {text, "Function"}}]), - FunEntry = gs:entry(Frame, [{pack_xy, {2,2}}]), - gs:label(Frame, [{pack_xy, {3,1}}, {label, {text, "Arity"}}]), - ArityEntry = gs:entry(Frame, [{pack_xy, {3,2}}]), - ButtonPacker = gs:frame(Frame, [{pack_xy, {2,4}}, - {packer_x, [{fixed, 60}, {fixed, 60}]}, - {packer_y, {fixed, 30}}]), - SearchButton = gs:button(ButtonPacker, [{label, {text, "Search"}}, - {pack_xy, {1,1}}]), - CancelButton = gs:button(ButtonPacker, [{label, {text, "Cancel"}}, - {pack_xy, {2,1}}]), - gs:config(Win, [{map, true}]), - gs:config(Frame, WH), - gs:config(ButtonPacker, WHB), - search_doc_plt_loop(State, CancelButton, SearchButton, ModEntry, - FunEntry, ArityEntry, Win, TopWin). - -search_doc_plt_loop(State, CancelButton, SearchButton, ModEntry, - FunEntry, ArityEntry, Win, TopWin) -> - receive - {gs, CancelButton, click, _, _} -> - gs:destroy(Win), - ok; - {gs, TopWin, destroy, _, _} -> - exit(normal); - {gs, SearchButton, click, _, _} -> - M = format_search(gs:read(ModEntry, text)), - F = format_search(gs:read(FunEntry, text)), - A = format_search(gs:read(ArityEntry, text)), - case dialyzer_plt:get_specs(State#gui_state.doc_plt, M, F, A) of - "" -> - error_sms(State, "No such function"), - search_doc_plt_loop(State, CancelButton, SearchButton, ModEntry, - FunEntry, ArityEntry, Win, TopWin); - NonEmptyString -> - gs:destroy(Win), - free_editor(State, "Content of PLT", NonEmptyString) - end - end. - -format_search([]) -> - '_'; -format_search(String) -> - try list_to_integer(String) - catch error:_ -> list_to_atom(String) - end. - -show_doc_plt(#gui_state{doc_plt = DocPLT} = State) -> - case dialyzer_plt:get_specs(DocPLT) of - "" -> error_sms(State, "No analysis has been made yet!\n"); - NonEmptyString -> free_editor(State, "Content of PLT", NonEmptyString) - end. - -free_editor(#gui_state{gs = GS, top = TopWin}, Title, Contents0) -> - Contents = lists:flatten(Contents0), - Tokens = string:tokens(Contents, "\n"), - NofLines = length(Tokens), - LongestLine = lists:max([length(X) || X <- Tokens]), - Height0 = NofLines * 25 + 80, - Height = if Height0 > 500 -> 500; true -> Height0 end, - Width0 = LongestLine * 7 + 60, - Width = if Width0 > 800 -> 800; true -> Width0 end, - WH = [{width, Width}, {height, Height}], - Win = gs:window(GS, [{title, Title}, {configure, true}, - {default, editor, {bg, white}} | WH]), - EmptySpace = {stretch, 1}, - Frame = gs:frame(Win, [{packer_x, [EmptySpace, {fixed, 60}, EmptySpace]}, - {packer_y, [EmptySpace, {fixed, 30}]} - | WH]), - Editor = gs:editor(Frame, [{pack_x, {1,3}}, {pack_y, 1}, - {font, {courier, 12}}, {vscroll, right}, - {wrap, word}, {enable, true}]), - Button = gs:button(Frame, [{label, {text, "Ok"}}, {pack_xy, {2,2}}]), - gs:config(Editor, [{insert, {insert, Contents}}]), - gs:config(Editor, [{enable, false}]), - gs:config(Win, [{map, true}]), - gs:config(Frame, WH), - show_info_loop(TopWin, Win, Frame, Button). - -%% ---- Common ---- - -show_info_loop(TopWin, Win, Frame, Button) -> - receive - {gs, Button, click, _, _} -> - gs:destroy(Win); - {gs, TopWin, destroy, _, _} -> - exit(normal); - {gs, Win, destroy, _, _} -> - ok; - {gs, Win, configure, _Data, [W, H|_]} -> - gs:config(Frame, [{width, W}, {height, H}]), - show_info_loop(TopWin, Win, Frame, Button) - end. - -include_dialog(#gui_state{gs = GS, options = Options}, Parent) -> - WH = [{width, 300}, {height, 400}], - Title = io_lib:format("Include Directories", []), - Win = gs:window(GS, [{title, Title}, {configure, true}, - {default, entry, {bg, white}}| WH]), - EmptySpace = {stretch, 1}, - Frame = gs:frame(Win, [{packer_x, [EmptySpace]}, - {packer_y, [{fixed, 30}, {fixed, 30}, {fixed, 30}, - EmptySpace, {fixed, 30}, {fixed, 30}]} - | WH]), - gs:label(Frame, [{pack_xy, {1,1}}, {label, {text, "Directory"}}]), - DirEntry = gs:entry(Frame, [{pack_xy, {1,2}}]), - ButtonPacker1 = gs:frame(Frame, [{pack_xy, {1,3}}, - {packer_x, [{fixed, 70}, {fixed, 70}, - EmptySpace]}, - {packer_y, {fixed, 30}}]), - AddButton = gs:button(ButtonPacker1, [{label, {text, "Add"}}, - {pack_xy, {1,1}}]), - Dirs = [io_lib:format("~s", [X]) || X <- Options#options.include_dirs], - DirBox = gs:listbox(Frame, [{pack_xy, {1,4}}, {vscroll, right}, - {bg, white}, {configure, true}, - {selectmode, multiple}, {items, Dirs}]), - ButtonPacker2 = gs:frame(Frame, [{pack_xy, {1,5}}, - {packer_x, [{fixed, 60}, {fixed, 70}, - EmptySpace]}, - {packer_y, {fixed, 30}}]), - DeleteButton = gs:button(ButtonPacker2, [{label, {text, "Delete"}}, - {pack_xy, {1,1}}]), - DeleteAllButton = gs:button(ButtonPacker2, [{label, {text, "Delete All"}}, - {pack_xy, {2,1}}]), - ButtonPacker3 = gs:frame(Frame, [{pack_xy, {1,6}}, - {packer_x, [EmptySpace, - {fixed, 60}, {fixed, 60}]}, - {packer_y, {fixed, 30}}]), - OkButton = gs:button(ButtonPacker3, [{label, {text, "Ok"}}, - {pack_xy, {2,1}}]), - CancelButton = gs:button(ButtonPacker3, [{label, {text, "Cancel"}}, - {pack_xy, {3,1}}]), - gs:config(Win, [{map, true}]), - gs:config(Frame, WH), - include_loop(Parent, Options, Frame, AddButton, DeleteAllButton, DeleteButton, - DirBox, DirEntry, OkButton, CancelButton, Win). - -include_loop(Parent, Options, Frame, AddButton, DeleteAllButton, DeleteButton, - DirBox, DirEntry, OkButton, CancelButton, Win) -> - receive - {gs, CancelButton, click, _, _} -> - gs:destroy(Win), - ok; - {gs, OkButton, click, _, _} -> - gs:destroy(Win), - Parent ! {new_options, Options}, - ok; - {gs, Win, configure, _Data, [W, H|_]} -> - gs:config(Frame, [{width, W}, {height, H}]), - include_loop(Parent, Options, Frame, AddButton, DeleteAllButton, - DeleteButton, DirBox, DirEntry, OkButton, CancelButton, Win); - {gs, AddButton, click, _, _} -> - Dirs = Options#options.include_dirs, - NewDirs = - case gs:read(DirEntry, text) of - [] -> Dirs; - Add -> [Add|Dirs] - end, - NewOptions = Options#options{include_dirs = NewDirs}, - gs:config(DirBox, [{items, NewDirs}]), - include_loop(Parent, NewOptions, Frame, AddButton, DeleteAllButton, - DeleteButton, DirBox, DirEntry, OkButton, CancelButton, Win); - {gs, DeleteAllButton, click, _, _} -> - gs:config(DirBox, [clear]), - NewOptions = Options#options{include_dirs = []}, - include_loop(Parent, NewOptions, Frame, AddButton, DeleteAllButton, - DeleteButton, DirBox, DirEntry, OkButton, CancelButton, Win); - {gs, DeleteButton, click, _, _} -> - NewOptions = - case gs:read(DirBox, selection) of - [] -> - Options; - List -> - lists:foreach(fun(X) -> gs:config(DirBox, [{del, X}]) end, - lists:sort(List)), - NewDirs = gs:read(DirBox, items), - Options#options{include_dirs = NewDirs} - end, - include_loop(Parent, NewOptions, Frame, AddButton, DeleteAllButton, - DeleteButton, DirBox, DirEntry, OkButton, CancelButton, Win); - {gs, Win, destroy, _, _} -> - ok - end. - -macro_dialog(#gui_state{gs = GS, options = Options}, Parent) -> - WH = [{width, 300}, {height, 400}], - Title = io_lib:format("Macro Definitions", []), - Win = gs:window(GS, [{title, Title}, {configure, true}, - {default, entry, {bg, white}}| WH]), - EmptySpace = {stretch, 1}, - Frame = gs:frame(Win, [{packer_x, [EmptySpace, EmptySpace]}, - {packer_y, [{fixed, 30}, {fixed, 30}, {fixed, 30}, - EmptySpace, {fixed, 30}, {fixed, 30}]} - | WH]), - gs:label(Frame, [{pack_xy, {1,1}}, {label, {text, "Macro"}}]), - MacroEntry = gs:entry(Frame, [{pack_xy, {1,2}}]), - gs:label(Frame, [{pack_xy, {2,1}}, {label, {text, "Term"}}]), - TermEntry = gs:entry(Frame, [{pack_xy, {2,2}}]), - ButtonPacker1 = gs:frame(Frame, [{pack_x, {1,2}}, {pack_y, 3}, - {packer_x, [{fixed, 70},{fixed, 70}, - EmptySpace]}, - {packer_y, {fixed, 30}}]), - AddButton = gs:button(ButtonPacker1, [{label, {text, "Add"}}, - {pack_xy, {1,1}}]), - Macros = [io_lib:format("~p = ~p",[X,Y]) || {X,Y} <- Options#options.defines], - MacroBox = gs:listbox(Frame, [{pack_x, {1,2}}, {pack_y, 4}, {vscroll, right}, - {bg, white}, {configure, true}, - {selectmode, multiple}, - {items, Macros}]), - ButtonPacker2 = gs:frame(Frame, [{pack_x, {1,2}}, {pack_y, 5}, - {packer_x, [{fixed, 60}, {fixed, 70}, - EmptySpace]}, - {packer_y, {fixed, 30}}]), - DeleteButton = gs:button(ButtonPacker2, [{label, {text, "Delete"}}, - {pack_xy, {1,1}}]), - DeleteAllButton = gs:button(ButtonPacker2, [{label, {text, "Delete All"}}, - {pack_xy, {2,1}}]), - ButtonPacker3 = gs:frame(Frame, [{pack_x, {1,2}}, {pack_y, 6}, - {packer_x, [EmptySpace, - {fixed, 60}, {fixed, 60}]}, - {packer_y, {fixed, 30}}]), - OkButton = gs:button(ButtonPacker3, [{label, {text, "Ok"}}, - {pack_xy, {2,1}}]), - CancelButton = gs:button(ButtonPacker3, [{label, {text, "Cancel"}}, - {pack_xy, {3,1}}]), - gs:config(Win, [{map, true}]), - gs:config(Frame, WH), - macro_loop(Parent, Options, Frame, AddButton, DeleteAllButton, DeleteButton, - MacroBox, MacroEntry, TermEntry, OkButton, CancelButton, Win). - -macro_loop(Parent, Options, Frame, AddButton, DeleteAllButton, DeleteButton, - MacroBox, MacroEntry, TermEntry, OkButton, CancelButton, Win) -> - receive - {gs, CancelButton, click, _, _} -> - gs:destroy(Win), - ok; - {gs, OkButton, click, _, _} -> - gs:destroy(Win), - Parent ! {new_options, Options}, - ok; - {gs, Win, configure, _Data, [W, H|_]} -> - gs:config(Frame, [{width, W}, {height, H}]), - macro_loop(Parent, Options, Frame, AddButton, DeleteAllButton, - DeleteButton, MacroBox, MacroEntry, TermEntry, OkButton, - CancelButton, Win); - {gs, AddButton, click, _, _} -> - Defines = Options#options.defines, - NewDefines = - case gs:read(MacroEntry, text) of - "" -> Defines; - Macro -> - Empty = [{text, ""}], - case gs:read(TermEntry, text) of - "" -> - gs:config(MacroEntry, Empty), - orddict:store(list_to_atom(Macro), true, Defines); - String -> - case parse(String) of - {ok, Term} -> - gs:config(MacroEntry, Empty), - gs:config(TermEntry, Empty), - orddict:store(list_to_atom(Macro), Term, Defines); - {error, _Reason} -> - Defines - end - end - end, - NewOptions = Options#options{defines = NewDefines}, - NewEntries = [io_lib:format("~p = ~p", [X, Y]) || {X, Y} <- NewDefines], - gs:config(MacroBox, [{items, NewEntries}]), - macro_loop(Parent, NewOptions, Frame, AddButton, DeleteAllButton, - DeleteButton, MacroBox, MacroEntry, TermEntry, OkButton, - CancelButton, Win); - {gs, DeleteAllButton, click, _, _} -> - gs:config(MacroBox, [clear]), - NewOptions = Options#options{defines = []}, - macro_loop(Parent, NewOptions, Frame, AddButton, DeleteAllButton, - DeleteButton, MacroBox, MacroEntry, TermEntry, OkButton, - CancelButton, Win); - {gs, DeleteButton, click, _, _} -> - NewOptions = - case gs:read(MacroBox, selection) of - [] -> - Options; - List -> - gs:config(MacroBox, [{selection, clear}]), - Fun = - fun(X) -> - Val = gs:read(MacroBox, {get, X}), - [MacroName|_] = re:split(Val, " ", [{return, list}]), - list_to_atom(MacroName) - end, - Delete = [Fun(X) || X <- List], - lists:foreach(fun(X) -> gs:config(MacroBox, [{del, X}]) end, - lists:reverse(lists:sort(List))), - Defines = Options#options.defines, - NewDefines = lists:foldl(fun(X, Acc) -> - orddict:erase(X, Acc) - end, - Defines, Delete), - Options#options{defines = NewDefines} - end, - macro_loop(Parent, NewOptions, Frame, AddButton, DeleteAllButton, - DeleteButton, MacroBox, MacroEntry, TermEntry, OkButton, - CancelButton, Win); - {gs, Win, destroy, _, _} -> - ok - end. - -parse(String) -> - case erl_scan:string(String ++ ".", 1) of - {ok, Ts, _} -> - case erl_parse:parse_exprs(Ts) of - {ok, [Expr]} -> - try erl_parse:normalise(Expr) - catch error:Reason -> {error, Reason} - end; - {error, E} -> - parse_error(E) - end; - {error, E, _} -> - parse_error(E) - end. - -parse_error(E) -> - S = io_lib:fwrite("Error parsing expression: ~P.", [E,15]), - {error, S}. - -%% ---------------------------------------------------------------- -%% -%% Run the analysis -%% - -start_analysis(State) -> - Analysis = build_analysis_record(State), - case get_anal_files(State, Analysis#analysis.start_from) of - error -> - Msg = "You must choose one or more files or dirs\n" - "before starting the analysis!", - error_sms(State, Msg), - config_gui_stop(State), - State; - {ok, Files} -> - Msg = "\n========== Starting Analysis ==========\n\n", - update_editor(State#gui_state.log, Msg), - NewAnalysis = Analysis#analysis{files = Files}, - run_analysis(State, NewAnalysis) - end. - -build_analysis_record(#gui_state{mode = Mode, menu = Menu, options = Options, - init_plt = InitPlt0}) -> - StartFrom = - case gs:read(Mode#mode.start_byte_code, select) of - true -> byte_code; - false -> src_code - end, - InitPlt = - case gs:read(Menu#menu.plt_empty, select) of - true -> dialyzer_plt:new(); - false -> InitPlt0 - end, - #analysis{defines = Options#options.defines, - include_dirs = Options#options.include_dirs, - plt = InitPlt, - start_from = StartFrom, - solvers = Options#options.solvers}. - -get_anal_files(#gui_state{chosen_box = ChosenBox}, StartFrom) -> - Files = gs:read(ChosenBox, items), - FilteredMods = - case StartFrom of - src_code -> filter_mods(Files, ".erl"); - byte_code -> filter_mods(Files, ".beam") - end, - FilteredDirs = [X || X <- Files, filelib:is_dir(X)], - case ordsets:union(FilteredMods, FilteredDirs) of - [] -> error; - Set -> {ok, Set} - end. - -run_analysis(State, Analysis) -> - config_gui_start(State), - Self = self(), - NewAnalysis = Analysis#analysis{doc_plt = dialyzer_plt:new()}, - LegalWarnings = find_legal_warnings(State), - Fun = - fun() -> - dialyzer_analysis_callgraph:start(Self, LegalWarnings, NewAnalysis) - end, - BackendPid = spawn_link(Fun), - State#gui_state{backend_pid = BackendPid}. - -find_legal_warnings(#gui_state{menu = #menu{warnings = Warnings}}) -> - ordsets:from_list([Tag || {Tag, GSItem} <- Warnings, - gs:read(GSItem, select) =:= true]). - -flush() -> - receive - _ -> flush() - after - 0 -> ok - end. - -update_editor(Editor, Msg) -> - gs:config(Editor, [{enable, true}]), - NofRows = gs:read(Editor, size), - gs:config(Editor, [{insertpos, 'end'}]), - gs:config(Editor, [{insert, {insert, Msg}}]), - NewNofRows = gs:read(Editor, size), - ScrollPos = gs:read(Editor, vscrollpos), - gs:config(Editor, [{vscrollpos, ScrollPos + NewNofRows - NofRows}]), - gs:config(Editor, [{enable, false}]). diff --git a/lib/hipe/tools/Makefile b/lib/hipe/tools/Makefile index 3ce8ad5dd7..ed80eb075b 100644 --- a/lib/hipe/tools/Makefile +++ b/lib/hipe/tools/Makefile @@ -42,7 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN) # ---------------------------------------------------- # Target Specs # ---------------------------------------------------- -MODULES = hipe_tool hipe_profile hipe_jit +MODULES = hipe_profile hipe_jit # hipe_timer HRL_FILES= @@ -110,5 +110,4 @@ realclean: clean # ---------------------------------------------------- $(EBIN)/hipe_ceach.beam: ../main/hipe.hrl -$(EBIN)/hipe_tool.beam: ../main/hipe.hrl diff --git a/lib/hipe/tools/hipe_tool.erl b/lib/hipe/tools/hipe_tool.erl deleted file mode 100644 index efcf073efa..0000000000 --- a/lib/hipe/tools/hipe_tool.erl +++ /dev/null @@ -1,525 +0,0 @@ -%% -*- erlang-indent-level: 2 -*- -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-2012. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Copyright (c) 2002 by Erik Johansson. -%% ==================================================================== -%% Module : hipe_tool -%% Purpose : -%% Notes : -%% History : * 2002-03-13 Erik Johansson ([email protected]): Created. -%% ==================================================================== -%% Exports : -%% -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - --module(hipe_tool). --compile([{nowarn_deprecated_function,{gs,button,3}}, - {nowarn_deprecated_function,{gs,config,2}}, - {nowarn_deprecated_function,{gs,destroy,1}}, - {nowarn_deprecated_function,{gs,editor,3}}, - {nowarn_deprecated_function,{gs,label,3}}, - {nowarn_deprecated_function,{gs,listbox,3}}, - {nowarn_deprecated_function,{gs,menu,3}}, - {nowarn_deprecated_function,{gs,menubar,3}}, - {nowarn_deprecated_function,{gs,menubutton,3}}, - {nowarn_deprecated_function,{gs,menuitem,2}}, - {nowarn_deprecated_function,{gs,start,0}}, - {nowarn_deprecated_function,{gs,window,3}}]). - --export([start/0]). - -%%--------------------------------------------------------------------- - --include("../main/hipe.hrl"). - -%%--------------------------------------------------------------------- - --define(WINDOW_WIDTH, 920). --define(WINDOW_HEIGHT, 460). --define(DEFAULT_BG_COLOR, {217,217,217}). --define(POLL_INTERVAL, 5000). --define(FONT, {screen, 12}). --define(HEADER_FONT, {screen, [bold], 12}). --define(NORMAL_FG_COLOR, {0,0,0}). - -%%--------------------------------------------------------------------- - --type fa() :: {atom(), arity()}. % {Fun,Arity} --type fa_address() :: {atom(), arity(), non_neg_integer()}. % {F,A,Address} - -%%--------------------------------------------------------------------- - --record(state, {win_created = false :: boolean(), - mindex = 0 :: integer(), - mod :: atom(), - funs = [] :: [fa()], - mods = [] :: [atom()], - options = [o2] :: comp_options(), - compiling = false :: 'false' | pid() - }). - -%%--------------------------------------------------------------------- - --spec start() -> pid(). - -start() -> - spawn(fun () -> init() end). - -init() -> - process_flag(trap_exit, true), - gs:start(), - S = init_window(#state{}), - loop(S). - --spec loop(#state{}) -> no_return(). - -loop(State) -> - receive - {gs, code_listbox, click, Data, [Idx, Txt | _]} -> - NewState = update_module_box(State,Idx,Data,Txt), - loop(NewState); - {gs, module_listbox, click, Data, [Idx, _Txt | _]} -> - NewState = update_fun(State,Idx,Data), - loop(NewState); - {gs, compmod, click, _, _} -> - loop(compile(State)); - {gs, prof, click, [], ["Turn off\nProfiling"]} -> - hipe_profile:prof_module_off(State#state.mod), - loop(update_module_box(State,State#state.mindex,State#state.mods,"")); - {gs, prof, click, [], _} -> - hipe_profile:prof_module(State#state.mod), - loop(update_module_box(State,State#state.mindex,State#state.mods,"")); - {gs, win, configure, _, _} -> - gs:config(win, [{width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}]), - loop(State); - - show_window when State#state.win_created =:= true -> - gs:config(win, [raise]), - loop(State); - show_window when State#state.win_created =:= false -> - loop((init_window(State))#state{win_created = true}); - - {gs, _Id, click, close_menu, _Args} -> - gs:destroy(win), - loop(State#state{win_created = false}); - {gs, _Id, keypress, _Data, [c, _, 0, 1 | _]} -> - gs:destroy(win), - loop(State#state{win_created = false}); - {gs, _Id, keypress, _Data, ['C', _, 1, 1 | _]} -> - gs:destroy(win), - loop(State#state{win_created = false}); - {gs, _Id, keypress, _Data, _Args} -> - loop(State); - {gs, _, destroy, _, _} -> - loop(State#state{win_created = false}); - - {compilation_done, _Res, Sender} -> - case State#state.compiling of - Sender -> - catch gs:config(compmod, [{enable, true}]), - update_text(compiling, ""), - loop(update_module_box(State, - State#state.mindex, - State#state.mods, "")); - _ -> - loop(State) - end; - - {'EXIT', _Pid, _Reason} -> - exit(normal); - _Other -> - io:format("HiPE window received message ~p ~n", [_Other]), - loop(State) - after - ?POLL_INTERVAL -> - loop(update_code_listbox(State)) - end. - --spec init_window(#state{}) -> #state{}. - -init_window(State) -> - create_window(State), - gs:config(win, [{map,true}]), - update_code_listbox(State#state{win_created = true}). - --spec create_window(#state{}) -> 'ok'. - -create_window(State) -> - gs:window(win, gs:start(), [{width, ?WINDOW_WIDTH}, - {height, ?WINDOW_HEIGHT}, - {bg, ?DEFAULT_BG_COLOR}, - {title, "[HiPE] Code list"}, - {configure, true}, - {destroy, true}, - {cursor, arrow}, - {keypress, true} - ]), - create_menu(), - Xpos = 4, - Ypos1 = 60, - Width = (?WINDOW_WIDTH - (Xpos*4)) div 3, - create_labels([{mods,Ypos1-20,"Loaded Modules"}], Xpos + 1 + 3), - Xpos2 = Xpos*2+Width, - create_labels([{mod,Ypos1-20,"Module:"++atom_to_list(State#state.mod)}, - {ver,Ypos1,""}, - {time,Ypos1+20,""}, - {native,Ypos1+40,""}, - {compiling,Ypos1+60,""}], Xpos2), - create_labels([{function,Ypos1-20,"Function:"}, - {nativefun,Ypos1,""}], Xpos*3+Width*2), - Ypos = 240, - Height1 = ?WINDOW_HEIGHT - Ypos1 - Xpos, - Height = ?WINDOW_HEIGHT - Ypos - Xpos, - gs:listbox(code_listbox, win, [{x, Xpos}, - {y, Ypos1}, - {width, Width}, - {height, Height1}, - {bg, {255,255,255}}, - {vscroll, right}, - {hscroll, true}, - {click, true}]), - gs:listbox(module_listbox, win, [{x, Xpos*2+Width}, - {y, Ypos}, - {width, Width}, - {height, Height}, - {bg, {255,255,255}}, - {vscroll, right}, - {hscroll, true}, - {click, true}]), - gs:listbox(profile_listbox, win, [{x, Xpos*3+Width*2}, - {y, Ypos1+40}, - {width, Width}, - {height, Height-60}, - {bg, {255,255,255}}, - {vscroll, right}, - {hscroll, true}, - {click, true}]), - gs:button(compmod,win,[{label,{text,"Compile\nModule"}}, - {justify,center}, - {x,Xpos*2+Width*1}, - {height,60}, - {y,Ypos-80}]), - gs:button(prof,win,[{label,{text,"Profile\nModule"}}, - {justify,center}, - {x,Xpos*2+Width*1+100}, - {height,60}, - {y,Ypos-80}]), - gs:button(clearprof,win,[{label, {text,"Clear\nProfile"}}, - {justify, center}, - {x, Xpos*2+Width*1+200}, - {height, 60}, - {y, Ypos-80}]), - gs:editor(edoc,win,[{x, Xpos*3+Width*2}, {y, Ypos}, - {width, Width}, {height, Height}, - {insert, {'end',"Edit this text!"}}, - {vscroll, right}, - {hscroll, true}, - {wrap, none}]), - ok. - --spec create_menu() -> 'ok'. - -create_menu() -> - gs:menubar(menubar, win, [{bg, ?DEFAULT_BG_COLOR}]), - create_sub_menus([{mbutt, fmenu, " File", - [{" Close Ctrl-C ",close_menu}]}, - {mbuttc,cmenu, " Compile ", - [{" Compile Module", comp_mod}]}, - {mbuttp,pmenu, " Profile ", - [{" Profile Module", prof_mod}]}, - {mbutte,emenu, " Edoc", [separator]}, - {mbutta,amenu, " Analyze ", [separator]}, - {mbuttb,bmenu, " Benchmark ", [separator]}, - {mbuttj,jmenu, " Jit ", [separator]}]), - ok. - -create_menuitems(Parent, [{Text,Data}|Rest]) -> - gs:menuitem(Parent, [{bg, ?DEFAULT_BG_COLOR}, - {fg, {178, 34, 34}}, - {label, {text, Text}}, - {data, Data}, - {underline, 1} - ]), - create_menuitems(Parent, Rest); -create_menuitems(Parent, [separator|Rest]) -> - gs:menuitem(Parent, [{itemtype, separator}]), - create_menuitems(Parent, Rest); -create_menuitems(_, []) -> ok. - -create_sub_menus([{Parent, Name, Text, Items}|Rest]) -> - BG = {bg, ?DEFAULT_BG_COLOR}, - FG = {fg, {178, 34, 34}}, % firebrick - Label = {label, {text, Text}}, - gs:menubutton(Parent, menubar, [BG, FG, Label, {underline, 1}]), - gs:menu(Name, Parent, [BG, FG]), - create_menuitems(Name, Items), - create_sub_menus(Rest); -create_sub_menus([]) -> ok. - -create_labels([{Name,Y,Text}|Rest], Xpos) -> - gs:label(Name, win, [{width, (?WINDOW_WIDTH - 16) div 3}, - {height, 20}, - {x, Xpos + 1 + 3}, - {y, Y}, - {bg, ?DEFAULT_BG_COLOR}, - {fg, ?NORMAL_FG_COLOR}, - {font, ?HEADER_FONT}, - {align, w}, - {label, {text, Text}} - ]), - create_labels(Rest,Xpos); -create_labels([],_) -> ok. - --spec update_code_listbox(#state{}) -> #state{}. - -update_code_listbox(State) -> - Mods = lists:sort(mods()), - case State#state.win_created of - false -> - State; - true -> - case Mods =:= State#state.mods of - true -> State; - false -> - update_text(mods, - "Loaded Modules ("++ - integer_to_list(length(Mods))++")"), - catch gs:config(code_listbox, [{data, Mods}, - {items, Mods}, - {selection, 0}]), - update_module_box(State#state{mods = Mods}, 0, Mods, "") - end - end. - --spec update_fun(#state{}, integer(), [mfa()]) -> #state{}. - -update_fun(State, Idx, Data) -> - case State#state.win_created of - false -> - State; - true -> - MFA = {M,F,A} = get_selection(Idx, Data, {?MODULE,start,0}), - update_text(function, "Function: "++mfa_to_string(MFA)), - case in_native(F, A, native_code(M)) of - true -> update_text(nativefun, "Native"); - false -> update_text(nativefun, "Emulated") - end, - State - end. - -get_selection(Idx, Data, Default) -> - try lists:nth(Idx+1, Data) catch _:_ -> Default end. - --spec update_module_box(#state{}, integer(), [atom()], string()) -> #state{}. - -update_module_box(State, Idx, Data, _Txt) -> - case State#state.win_created of - false -> - State; - true -> - Mod = get_selection(Idx, Data, hipe_tool), - %% io:format("~w\n", [Mod:module_info()]), - Info = Mod:module_info(), - Funs = lists:usort(funs(Mod)), - MFAs = mfas(Mod, Funs), - ModText = atom_to_list(Mod), - update_text(mod, "Module:"++ModText), - update_text(compmod, "Compile\nModule\n"++ModText), - Options = get_compile(Info), - update_text(ver, get_version(Options)), - update_text(time, get_time(Options)), - NativeCode = native_code(Mod), - - Prof = is_profiled(Mod), - if Prof -> update_text(prof, "Turn off\nProfiling"); - true -> update_text(prof, "Profile\n"++ModText) - end, - - Mode = get_mode(Funs, NativeCode), - - update_text(native, Mode), - Items = fun_names(Mod, Funs, NativeCode, Prof), - - Selection = {selection, 0}, - catch gs:config(module_listbox, [{data, MFAs}, - {items, Items}, - Selection]), - ProfData = [mfa_to_string(element(1, X)) ++ " " ++ - integer_to_list(element(2,X)) - || X <- hipe_profile:res(), element(2, X) > 0], - catch gs:config(profile_listbox, [{data, ProfData}, - {items, ProfData}, - Selection]), - get_edoc(Mod), - update_fun(State#state{mindex = Idx, mod = Mod, funs = Funs}, 0, MFAs) - end. - -update_text(Lab, Text) -> - catch gs:config(Lab, [{label, {text, Text}}]). - -%%--------------------------------------------------------------------- -%% @doc Returns a list of all loaded modules. -%%--------------------------------------------------------------------- - --spec mods() -> [atom()]. - -mods() -> - [Mod || {Mod,_File} <- code:all_loaded()]. - --spec funs(module()) -> [fa()]. - -funs(Mod) -> - Mod:module_info(functions). - --spec native_code(module()) -> [fa_address()]. - -native_code(Mod) -> - Mod:module_info(native_addresses). - --spec mfas(atom(), [fa()]) -> [mfa()]. - -mfas(Mod, Funs) -> - [{Mod,F,A} || {F,A} <- Funs]. - --spec fun_names(atom(), [fa()], [fa_address()], boolean()) -> [string()]. - -fun_names(M, Funs, NativeCode, Prof) -> - [atom_to_list(F) ++ "/" ++ integer_to_list(A) - ++ - (case in_native(F, A, NativeCode) of - true -> " [native] "; - false -> "" - end) - ++ - if Prof -> - (catch integer_to_list(hipe_bifs:call_count_get({M,F,A}))); - true -> "" - end - || {F,A} <- Funs]. - --spec in_native(atom(), arity(), [fa_address()]) -> boolean(). - -in_native(F, A, NativeCode) -> - lists:any(fun({Fun,Arity,_}) -> - (Fun =:= F andalso Arity =:= A) - end, - NativeCode). - --spec mfa_to_string(mfa()) -> [char(),...]. - -mfa_to_string({M,F,A}) -> - atom_to_list(M) ++ ":" ++ atom_to_list(F) ++ "/" ++ integer_to_list(A). - -get_mode(Funs, NativeCode) -> - case NativeCode of - [] -> "Emulated"; - InNative when is_list(InNative) -> - if length(InNative) =:= length(Funs) -> - "Native"; - true -> "Mixed" - end - end. - -get_time(Comp) -> - case lists:keyfind(time, 1, Comp) of - {_, {Y,Month,D,H,Min,S}} -> - integer_to_list(Y) ++ - "-" ++ integer_to_list(Month) ++ - "-" ++ integer_to_list(D) ++ " " ++ - integer_to_list(H) ++ ":" ++ integer_to_list(Min) ++ - ":" ++ integer_to_list(S); - false -> "" - end. - -get_version(Comp) -> - case lists:keyfind(version, 1, Comp) of - {_, V} when is_list(V) -> V; - false -> "" - end. - -get_cwd(Options) -> - case lists:keyfind(cwd, 1, Options) of - {_, V} when is_atom(V) -> atom_to_list(V); - {_, V} -> V; - false -> "" - end. - -get_options(Comp) -> - case lists:keyfind(options, 1, Comp) of - {_, V} when is_list(V) -> V; - false -> "" - end. - -get_compile(Info) -> - case lists:keyfind(compile, 1, Info) of - {_, O} when is_list(O) -> O; - false -> [] - end. - --spec is_profiled(atom()) -> boolean(). - -is_profiled(Mod) -> - case hipe_bifs:call_count_get({Mod,module_info,0}) of - false -> false; - C when is_integer(C) -> true - end. - --spec compile(#state{}) -> #state{}. - -compile(State) -> - catch gs:config(compmod, [{enable, false}]), - update_text(compiling, "Compiling..."), - Parent = self(), - P = spawn(fun() -> c(Parent, State#state.mod, State#state.options) end), - State#state{compiling = P}. - --spec c(pid(), atom(), comp_options()) -> 'ok'. - -c(Parent, Mod, Options) -> - Res = hipe:c(Mod, Options), - Parent ! {compilation_done,Res,self()}, - ok. - -get_edoc(Mod) -> - Info = Mod:module_info(), - Comp = get_compile(Info), - Options = get_options(Comp), - Dir = get_cwd(Options), - File = - case Dir of - "" -> atom_to_list(Mod) ++ ".erl"; - _ -> Dir ++"/" ++ atom_to_list(Mod) ++ ".erl" - end, - %% io:format("Get ~s\n", [File]), - Text = try edoc(File, [{xml_export,xmerl_text}, no_output]) - catch _:_ -> "error" - end, - gs:config(edoc, {enable, true}), - gs:config(edoc, clear), - gs:config(edoc, {insert, {insert, Text}}), - gs:config(edoc, {enable, false}), - ok. - -edoc(Name, Opts) -> - Doc = edoc:get_doc(Name, Opts), - %% Comments = edoc:read_comments(Name, Opts), - %% Text = edoc:forms(Forms, Comments, Name, Opts), - edoc:layout(Doc, Opts), - ok. |