diff options
Diffstat (limited to 'lib/tools')
-rw-r--r-- | lib/tools/emacs/Makefile | 1 | ||||
-rw-r--r-- | lib/tools/emacs/README | 9 | ||||
-rw-r--r-- | lib/tools/emacs/erlang-eunit.el | 355 | ||||
-rw-r--r-- | lib/tools/emacs/erlang-flymake.el | 102 | ||||
-rw-r--r-- | lib/tools/emacs/erlang-start.el | 5 | ||||
-rw-r--r-- | lib/tools/emacs/erlang.el | 253 | ||||
-rw-r--r-- | lib/tools/emacs/test.erl.indented | 79 | ||||
-rw-r--r-- | lib/tools/emacs/test.erl.orig | 83 | ||||
-rw-r--r-- | lib/tools/src/xref_base.erl | 174 | ||||
-rw-r--r-- | lib/tools/src/xref_compiler.erl | 133 | ||||
-rw-r--r-- | lib/tools/src/xref_reader.erl | 52 | ||||
-rw-r--r-- | lib/tools/test/xref_SUITE.erl | 334 | ||||
-rw-r--r-- | lib/tools/test/xref_SUITE_data/read/read.erl | 12 | ||||
-rw-r--r-- | lib/tools/vsn.mk | 12 |
14 files changed, 1060 insertions, 544 deletions
diff --git a/lib/tools/emacs/Makefile b/lib/tools/emacs/Makefile index 0028df247c..8533488463 100644 --- a/lib/tools/emacs/Makefile +++ b/lib/tools/emacs/Makefile @@ -42,6 +42,7 @@ EMACS_FILES= \ erlang_appwiz \ erlang-start \ erlang-eunit \ + erlang-flymake \ erlang README_FILES= README diff --git a/lib/tools/emacs/README b/lib/tools/emacs/README index ca068d04c4..cc107dcd41 100644 --- a/lib/tools/emacs/README +++ b/lib/tools/emacs/README @@ -42,7 +42,14 @@ Files\erl-<Ver>: (setq erlang-root-dir "C:/Program Files/erl<Ver>") (setq exec-path (cons "C:/Program Files/erl<Ver>/bin" exec-path)) (require 'erlang-start) - +Miscellaneous addons +-------------------- + +In order to check erlang source code on the fly, add the following +line to your .emacs file (after erlang-start, see above). See +erlang-flymake.el for more information on how to customize the syntax +check. + (require 'erlang-flymake) diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el index b2598f93e6..f2c0db67dd 100644 --- a/lib/tools/emacs/erlang-eunit.el +++ b/lib/tools/emacs/erlang-eunit.el @@ -23,8 +23,22 @@ (eval-when-compile (require 'cl)) -(defvar erlang-eunit-separate-src-and-test-directories t - "*Whether or not to keep source and EUnit test files in separate directories") +(defvar erlang-eunit-src-candidate-dirs '("../src" ".") + "*Name of directories which to search for source files matching +an EUnit test file. The first directory in the list will be used, +if there is no match.") + +(defvar erlang-eunit-test-candidate-dirs '("../test" ".") + "*Name of directories which to search for EUnit test files matching +a source file. The first directory in the list will be used, +if there is no match.") + +(defvar erlang-eunit-autosave nil + "*Set to non-nil to automtically save unsaved buffers before running tests. +This is useful, reducing the save-compile-load-test cycle to one keychord.") + +(defvar erlang-eunit-recent-info '((mode . nil) (module . nil) (test . nil) (cover . nil)) + "Info about the most recent running of an EUnit test representation.") ;;; ;;; Switch between src/EUnit test buffers @@ -44,7 +58,6 @@ buffer and vice versa" "Open the EUnit test file which corresponds to a src file" (find-file-other-window (erlang-eunit-test-filename src-file-path))) - ;;; ;;; Open the src file which corresponds to the an EUnit test file ;;; @@ -55,37 +68,55 @@ buffer and vice versa" ;;; Return the name and path of the EUnit test file ;;, (input may be either the source filename itself or the EUnit test filename) (defun erlang-eunit-test-filename (file-path) - (erlang-eunit-rewrite-filename file-path "test" "_tests")) + (if (erlang-eunit-test-file-p file-path) + file-path + (erlang-eunit-rewrite-filename file-path erlang-eunit-test-candidate-dirs))) ;;; Return the name and path of the source file ;;, (input may be either the source filename itself or the EUnit test filename) (defun erlang-eunit-src-filename (file-path) - (erlang-eunit-rewrite-filename file-path "src" "")) + (if (erlang-eunit-src-file-p file-path) + file-path + (erlang-eunit-rewrite-filename file-path erlang-eunit-src-candidate-dirs))) ;;; Rewrite a filename from the src or test filename to the other -(defun erlang-eunit-rewrite-filename (orig-file-path dest-dirname dest-suffix) - (let* ((root-dir-name (erlang-eunit-file-root-dir-name orig-file-path)) - (src-module-name (erlang-eunit-source-module-name orig-file-path)) - (dest-base-name (concat src-module-name dest-suffix ".erl")) - (dest-dir-name-1 (file-name-directory orig-file-path)) - (dest-dir-name-2 (filename-join root-dir-name dest-dirname)) - (dest-file-name-1 (filename-join dest-dir-name-1 dest-base-name)) - (dest-file-name-2 (filename-join dest-dir-name-2 dest-base-name))) - ;; This function tries to be a bit intelligent: - ;; * if there already is a test (or source) file in the same - ;; directory as a source (or test) file, it'll be picked - ;; * if there already is a test (or source) file in a separate - ;; test (or src) directory, it'll be picked - ;; * otherwise it'll resort to whatever alternative (same or - ;; separate directories) that the user has chosen - (cond ((file-readable-p dest-file-name-1) - dest-file-name-1) - ((file-readable-p dest-file-name-2) - dest-file-name-2) - (erlang-eunit-separate-src-and-test-directories - dest-file-name-2) - (t - dest-file-name-1)))) +(defun erlang-eunit-rewrite-filename (orig-file-path candidate-dirs) + (or (erlang-eunit-locate-buddy orig-file-path candidate-dirs) + (erlang-eunit-buddy-file-path orig-file-path (car candidate-dirs)))) + +;;; Search for a file's buddy file (a source file's EUnit test file, +;;; or an EUnit test file's source file) in a list of candidate +;;; directories. +(defun erlang-eunit-locate-buddy (orig-file-path candidate-dirs) + (when candidate-dirs + (let ((buddy-file-path (erlang-eunit-buddy-file-path + orig-file-path + (car candidate-dirs)))) + (if (file-readable-p buddy-file-path) + buddy-file-path + (erlang-eunit-locate-buddy orig-file-path (cdr candidate-dirs)))))) + +(defun erlang-eunit-buddy-file-path (orig-file-path buddy-dir-name) + (let* ((orig-dir-name (file-name-directory orig-file-path)) + (buddy-dir-name (file-truename + (filename-join orig-dir-name buddy-dir-name))) + (buddy-base-name (erlang-eunit-buddy-basename orig-file-path))) + (filename-join buddy-dir-name buddy-base-name))) + +;;; Return the basename of the buddy file: +;;; /tmp/foo/src/x.erl --> x_tests.erl +;;; /tmp/foo/test/x_tests.erl --> x.erl +(defun erlang-eunit-buddy-basename (file-path) + (let ((src-module-name (erlang-eunit-source-module-name file-path))) + (cond + ((erlang-eunit-src-file-p file-path) + (concat src-module-name "_tests.erl")) + ((erlang-eunit-test-file-p file-path) + (concat src-module-name ".erl"))))) + +;;; Checks whether a file is a source file or not +(defun erlang-eunit-src-file-p (file-path) + (not (erlang-eunit-test-file-p file-path))) ;;; Checks whether a file is a EUnit test file or not (defun erlang-eunit-test-file-p (file-path) @@ -96,23 +127,17 @@ buffer and vice versa" ;;; /tmp/foo/test/x_tests.erl --> x (defun erlang-eunit-source-module-name (file-path) (interactive) - (let* ((file-name (file-name-nondirectory file-path)) - (base-name (file-name-sans-extension file-name))) - (if (string-match "^\\(.+\\)_tests$" base-name) - (substring base-name (match-beginning 1) (match-end 1)) - base-name))) - -;;; Return the directory name which is common to both src and test -;;; /tmp/foo/src/x.erl --> /tmp/foo -;;; /tmp/foo/test/x_tests.erl --> /tmp/foo -(defun erlang-eunit-file-root-dir-name (file-path) - (erlang-eunit-dir-parent-dirname (file-name-directory file-path))) - -;;; Return the parent directory name of a directory -;;; /tmp/foo/ --> /tmp -;;; /tmp/foo --> /tmp -(defun erlang-eunit-dir-parent-dirname (dir-name) - (file-name-directory (directory-file-name dir-name))) + (let ((module-name (erlang-eunit-module-name file-path))) + (if (string-match "^\\(.+\\)_tests$" module-name) + (substring module-name (match-beginning 1) (match-end 1)) + module-name))) + +;;; Return the module name of the file +;;; /tmp/foo/src/x.erl --> x +;;; /tmp/foo/test/x_tests.erl --> x_tests +(defun erlang-eunit-module-name (file-path) + (interactive) + (file-name-sans-extension (file-name-nondirectory file-path))) ;;; Older emacsen don't have string-match-p. (defun erlang-eunit-string-match-p (regexp string &optional start) @@ -128,25 +153,158 @@ buffer and vice versa" (concat dir file) (concat dir "/" file))) +;;; Get info about the most recent running of EUnit +(defun erlang-eunit-recent (key) + (cdr (assq key erlang-eunit-recent-info))) + +;;; Record info about the most recent running of EUnit +;;; Known modes are 'module-mode and 'test-mode +(defun erlang-eunit-record-recent (mode module test) + (setcdr (assq 'mode erlang-eunit-recent-info) mode) + (setcdr (assq 'module erlang-eunit-recent-info) module) + (setcdr (assq 'test erlang-eunit-recent-info) test)) + +;;; Record whether the most recent running of EUnit included cover +;;; compilation +(defun erlang-eunit-record-recent-compile (under-cover) + (setcdr (assq 'cover erlang-eunit-recent-info) under-cover)) + +;;; Determine options for EUnit. +(defun erlang-eunit-opts () + (if current-prefix-arg ", [verbose]" "")) + +;;; Determine current test function +(defun erlang-eunit-current-test () + (save-excursion + (erlang-end-of-function 1) + (erlang-beginning-of-function 1) + (erlang-name-of-function))) + +(defun erlang-eunit-simple-test-p (test-name) + (if (erlang-eunit-string-match-p "^\\(.+\\)_test$" test-name) t nil)) + +(defun erlang-eunit-test-generator-p (test-name) + (if (erlang-eunit-string-match-p "^\\(.+\\)_test_$" test-name) t nil)) + +;;; Run one EUnit test +(defun erlang-eunit-run-test (module-name test-name) + (let ((command + (cond ((erlang-eunit-simple-test-p test-name) + (format "eunit:test({%s, %s}%s)." + module-name test-name (erlang-eunit-opts))) + ((erlang-eunit-test-generator-p test-name) + (format "eunit:test({generator, %s, %s}%s)." + module-name test-name (erlang-eunit-opts))) + (t (format "%% WARNING: '%s' is not a test function" test-name))))) + (erlang-eunit-record-recent 'test-mode module-name test-name) + (erlang-eunit-inferior-erlang-send-command command))) + ;;; Run EUnit tests for the current module -(defun erlang-eunit-run-tests () - "Run the EUnit test suite for the current module. +(defun erlang-eunit-run-module-tests (module-name) + (let ((command (format "eunit:test(%s%s)." module-name (erlang-eunit-opts)))) + (erlang-eunit-record-recent 'module-mode module-name nil) + (erlang-eunit-inferior-erlang-send-command command))) + +(defun erlang-eunit-compile-and-run-recent () + "Compile the source and test files and repeat the most recent EUnit test run. -With prefix arg, runs tests with the verbose flag set." +With prefix arg, compiles for debug and runs tests with the verbose flag set." (interactive) - (let* ((module-name (erlang-add-quotes-if-needed - (erlang-eunit-source-module-name buffer-file-name))) - (opts (if current-prefix-arg ", [verbose]" "")) - (command (format "eunit:test(%s%s)." module-name opts))) - (erlang-eunit-inferior-erlang-send-command command))) + (case (erlang-eunit-recent 'mode) + ('test-mode + (erlang-eunit-compile-and-test + 'erlang-eunit-run-test (list (erlang-eunit-recent 'module) + (erlang-eunit-recent 'test)))) + ('module-mode + (erlang-eunit-compile-and-test + 'erlang-eunit-run-module-tests (list (erlang-eunit-recent 'module)) + (erlang-eunit-recent 'cover))) + (t (error "EUnit has not yet been run. Please run a test first.")))) + +(defun erlang-eunit-cover-compile () + "Cover compile current module." + (interactive) + (let* ((erlang-compile-extra-opts + (append (list 'debug_info) erlang-compile-extra-opts)) + (module-name + (erlang-add-quotes-if-needed + (erlang-eunit-module-name buffer-file-name))) + (compile-command + (format "cover:compile_beam(%s)." module-name))) + (erlang-compile) + (if (erlang-eunit-last-compilation-successful-p) + (erlang-eunit-inferior-erlang-send-command compile-command)))) + +(defun erlang-eunit-analyze-coverage () + "Analyze the data collected by cover tool for the module in the +current buffer. + +Assumes that the module has been cover compiled prior to this +call. This function will do two things: print the number of +covered and uncovered functions in the erlang shell and display a +new buffer called *<module name> coverage* which shows the source +code along with the coverage analysis results." + (interactive) + (let* ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-module-name buffer-file-name))) + (tmp-filename (make-temp-file "cover")) + (analyze-command (format "cover:analyze_to_file(%s, \"%s\"). " + module-name tmp-filename)) + (buf-name (format "*%s coverage*" module-name))) + (erlang-eunit-inferior-erlang-send-command analyze-command) + ;; The purpose of the following snippet is to get the result of the + ;; analysis from a file into a new buffer (or an old, if one with + ;; the specified name already exists). Also we want the erlang-mode + ;; *and* view-mode to be enabled. + (save-excursion + (let ((buf (get-buffer-create (format "*%s coverage*" module-name)))) + (set-buffer buf) + (setq buffer-read-only nil) + (insert-file-contents tmp-filename nil nil nil t) + (if (= (buffer-size) 0) + (kill-buffer buf) + ;; FIXME: this would be a good place to enable (emacs-mode) + ;; to get some nice syntax highlighting in the + ;; coverage report, but it doesn't play well with + ;; flymake. Leave it off for now. + (view-buffer buf)))) + (delete-file tmp-filename))) + +(defun erlang-eunit-compile-and-run-current-test () + "Compile the source and test files and run the current EUnit test. -;;; Compile source and EUnit test file and finally run EUnit tests for -;;; the current module -(defun erlang-eunit-compile-and-run-tests () - "Compile the source and test files and run the EUnit test suite. +With prefix arg, compiles for debug and runs tests with the verbose flag set." + (interactive) + (let ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-module-name buffer-file-name))) + (test-name (erlang-eunit-current-test))) + (erlang-eunit-compile-and-test + 'erlang-eunit-run-test (list module-name test-name)))) + +(defun erlang-eunit-compile-and-run-module-tests () + "Compile the source and test files and run all EUnit tests in the module. With prefix arg, compiles for debug and runs tests with the verbose flag set." (interactive) + (let ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-source-module-name buffer-file-name)))) + (erlang-eunit-compile-and-test + 'erlang-eunit-run-module-tests (list module-name)))) + +;;; Compile source and EUnit test file and finally run EUnit tests for +;;; the current module +(defun erlang-eunit-compile-and-test (test-fun test-args &optional under-cover) + "Compile the source and test files and run the EUnit test suite. + +If under-cover is set to t, the module under test is compile for +code coverage analysis. If under-cover is left out or not set, +coverage analysis is disabled. The result of the code coverage +is both printed to the erlang shell (the number of covered vs +uncovered functions in a module) and written to a buffer called +*<module> coverage* (which shows the source code for the module +and the number of times each line is covered). +With prefix arg, compiles for debug and runs tests with the verbose flag set." + (erlang-eunit-record-recent-compile under-cover) (let ((src-filename (erlang-eunit-src-filename buffer-file-name)) (test-filename (erlang-eunit-test-filename buffer-file-name))) @@ -154,7 +312,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." ;; below, is to ask the question about saving buffers only once, ;; instead of possibly several: one for each file to compile, ;; for instance for both x.erl and x_tests.erl. - (save-some-buffers) + (save-some-buffers erlang-eunit-autosave) (flet ((save-some-buffers (&optional any) nil)) ;; Compilation of the source file is mandatory (the file must @@ -162,23 +320,56 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." ;; test file on the other hand, is optional, since eunit tests may ;; be placed in the source file instead. Any compilation error ;; will prevent the subsequent steps to be run (hence the `and') - (and (erlang-eunit-compile-file src-filename) + (and (erlang-eunit-compile-file src-filename under-cover) (if (file-readable-p test-filename) (erlang-eunit-compile-file test-filename) t) - (erlang-eunit-run-tests))))) + (apply test-fun test-args) + (if under-cover + (save-excursion + (set-buffer (find-file-noselect src-filename)) + (erlang-eunit-analyze-coverage))))))) + +(defun erlang-eunit-compile-and-run-module-tests-under-cover () + "Compile the source and test files and run the EUnit test suite and measure +code coverage. + +With prefix arg, compiles for debug and runs tests with the verbose flag set." + (interactive) + (let ((module-name (erlang-add-quotes-if-needed + (erlang-eunit-source-module-name buffer-file-name)))) + (erlang-eunit-compile-and-test + 'erlang-eunit-run-module-tests (list module-name) t))) -(defun erlang-eunit-compile-file (file-path) +(defun erlang-eunit-compile-file (file-path &optional under-cover) (if (file-readable-p file-path) (save-excursion - (set-buffer (find-file-noselect file-path)) - (erlang-compile) - (erlang-eunit-last-compilation-successful-p)) + (set-buffer (find-file-noselect file-path)) + ;; In order to run a code coverage analysis on a + ;; module, we have two options: + ;; + ;; * either compile the module with cover:compile instead of the + ;; regular compiler + ;; + ;; * or first compile the module with the regular compiler (but + ;; *with* debug_info) and then compile it for coverage + ;; analysis using cover:compile_beam. + ;; + ;; We could accomplish the first by changing the + ;; erlang-compile-erlang-function to cover:compile, but there's + ;; a risk that that's used for other purposes. Therefore, a + ;; safer alternative (although with more steps) is to add + ;; debug_info to the list of compiler options and go for the + ;; second alternative. + (if under-cover + (erlang-eunit-cover-compile) + (erlang-compile)) + (erlang-eunit-last-compilation-successful-p)) (let ((msg (format "Could not read %s" file-path))) - (erlang-eunit-inferior-erlang-send-command + (erlang-eunit-inferior-erlang-send-command (format "%% WARNING: %s" msg)) (error msg)))) - + (defun erlang-eunit-last-compilation-successful-p () (save-excursion (set-buffer inferior-erlang-buffer) @@ -187,7 +378,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." (lambda (re) (let ((continue t) (result t)) (while continue ; ignore warnings, stop at errors - (if (re-search-forward re (point-max) t) + (if (re-search-forward re (point-max) t) (if (erlang-eunit-is-compilation-warning) t (setq result nil) @@ -198,7 +389,7 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." (mapcar (lambda (e) (car e)) erlang-error-regexp-alist)))) (defun erlang-eunit-is-compilation-warning () - (erlang-eunit-string-match-p + (erlang-eunit-string-match-p "[0-9]+: Warning:" (buffer-substring (line-beginning-position) (line-end-position)))) @@ -224,22 +415,22 @@ With prefix arg, compiles for debug and runs tests with the verbose flag set." ;;; Key bindings ;;;==================================================================== -(defvar erlang-eunit-toggle-src-and-test-file-other-window-key "\C-c\C-et" - "*Key to which the `erlang-eunit-toggle-src-and-test-file-other-window' -function will be bound.") -(defvar erlang-eunit-compile-and-run-tests-key "\C-c\C-ek" - "*Key to which the `erlang-eunit-compile-and-run-tests' -function will be bound.") +(defconst erlang-eunit-key-bindings + '(("\C-c\C-et" erlang-eunit-toggle-src-and-test-file-other-window) + ("\C-c\C-ek" erlang-eunit-compile-and-run-module-tests) + ("\C-c\C-ej" erlang-eunit-compile-and-run-current-test) + ("\C-c\C-el" erlang-eunit-compile-and-run-recent) + ("\C-c\C-ec" erlang-eunit-compile-and-run-module-tests-under-cover) + ("\C-c\C-ev" erlang-eunit-cover-compile) + ("\C-c\C-ea" erlang-eunit-analyze-coverage))) (defun erlang-eunit-add-key-bindings () - (erlang-eunit-ensure-keymap-for-key - erlang-eunit-toggle-src-and-test-file-other-window-key) - (local-set-key erlang-eunit-toggle-src-and-test-file-other-window-key - 'erlang-eunit-toggle-src-and-test-file-other-window) - (erlang-eunit-ensure-keymap-for-key - erlang-eunit-compile-and-run-tests-key) - (local-set-key erlang-eunit-compile-and-run-tests-key - 'erlang-eunit-compile-and-run-tests)) + (dolist (binding erlang-eunit-key-bindings) + (erlang-eunit-bind-key (car binding) (cadr binding)))) + +(defun erlang-eunit-bind-key (key function) + (erlang-eunit-ensure-keymap-for-key key) + (local-set-key key function)) (defun erlang-eunit-ensure-keymap-for-key (key-seq) (let ((prefix-keys (butlast (append key-seq nil))) diff --git a/lib/tools/emacs/erlang-flymake.el b/lib/tools/emacs/erlang-flymake.el new file mode 100644 index 0000000000..bc368e9454 --- /dev/null +++ b/lib/tools/emacs/erlang-flymake.el @@ -0,0 +1,102 @@ +;; erlang-flymake.el +;; +;; Syntax check erlang source code on the fly (integrates with flymake). +;; +;; Start using flymake with erlang by putting the following somewhere +;; in your .emacs file: +;; +;; (require 'erlang-flymake) +;; +;; Flymake is rather eager and does its syntax checks frequently by +;; default and if you are bothered by this, you might want to put the +;; following in your .emacs as well: +;; +;; (erlang-flymake-only-on-save) +;; +;; There are a couple of variables which control the compilation options: +;; * erlang-flymake-get-code-path-dirs-function +;; * erlang-flymake-get-include-dirs-function +;; * erlang-flymake-extra-opts +;; +;; This code is inspired by http://www.emacswiki.org/emacs/FlymakeErlang. + +(require 'flymake) +(eval-when-compile + (require 'cl)) + +(defvar erlang-flymake-command + "erlc" + "The command that will be used to perform the syntax check") + +(defvar erlang-flymake-get-code-path-dirs-function + 'erlang-flymake-get-code-path-dirs + "Return a list of ebin directories to add to the code path.") + +(defvar erlang-flymake-get-include-dirs-function + 'erlang-flymake-get-include-dirs + "Return a list of include directories to add to the compiler options.") + +(defvar erlang-flymake-extra-opts + (list "+warn_obsolete_guard" + "+warn_unused_import" + "+warn_shadow_vars" + "+warn_export_vars" + "+strong_validation" + "+report") + "A list of options that will be passed to the compiler") + +(defun erlang-flymake-only-on-save () + "Trigger flymake only when the buffer is saved (disables syntax +check on newline and when there are no changes)." + (interactive) + ;; There doesn't seem to be a way of disabling this; set to the + ;; largest int available as a workaround (most-positive-fixnum + ;; equates to 8.5 years on my machine, so it ought to be enough ;-) ) + (setq flymake-no-changes-timeout most-positive-fixnum) + (setq flymake-start-syntax-check-on-newline nil)) + + +(defun erlang-flymake-get-code-path-dirs () + (list (concat (erlang-flymake-get-app-dir) "ebin"))) + +(defun erlang-flymake-get-include-dirs () + (list (concat (erlang-flymake-get-app-dir) "include"))) + +(defun erlang-flymake-get-app-dir () + (let ((src-path (file-name-directory (buffer-file-name)))) + (file-name-directory (directory-file-name src-path)))) + +(defun erlang-flymake-init () + (let* ((temp-file + (flet ((flymake-get-temp-dir () (erlang-flymake-temp-dir))) + (flymake-init-create-temp-buffer-copy + 'flymake-create-temp-with-folder-structure))) + (code-dir-opts + (erlang-flymake-flatten + (mapcar (lambda (dir) (list "-pa" dir)) + (funcall erlang-flymake-get-code-path-dirs-function)))) + (inc-dir-opts + (erlang-flymake-flatten + (mapcar (lambda (dir) (list "-I" dir)) + (funcall erlang-flymake-get-include-dirs-function)))) + (compile-opts + (append inc-dir-opts + code-dir-opts + erlang-flymake-extra-opts))) + (list erlang-flymake-command (append compile-opts (list temp-file))))) + +(defun erlang-flymake-temp-dir () + ;; Squeeze the user's name in there in order to make sure that files + ;; for two users who are working on the same computer (like a linux + ;; box) don't collide + (format "%s/flymake-%s" temporary-file-directory user-login-name)) + +(defun erlang-flymake-flatten (list) + (apply #'append list)) + +(add-to-list 'flymake-allowed-file-name-masks + '("\\.erl\\'" erlang-flymake-init)) +(add-hook 'erlang-mode-hook 'flymake-mode) + +(provide 'erlang-flymake) +;; erlang-flymake ends here diff --git a/lib/tools/emacs/erlang-start.el b/lib/tools/emacs/erlang-start.el index 542e81f24c..bbcea3e46a 100644 --- a/lib/tools/emacs/erlang-start.el +++ b/lib/tools/emacs/erlang-start.el @@ -90,6 +90,11 @@ (or (assoc (car b) auto-mode-alist) (setq auto-mode-alist (cons b auto-mode-alist)))) +;; +;; Associate files using interpreter "escript" with Erlang mode. +;; + +(add-to-list 'interpreter-mode-alist (cons "escript" 'erlang-mode)) ;; ;; Ignore files ending in ".jam", ".vee", and ".beam" when performing diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el index 0132587d28..91acfdf2b6 100644 --- a/lib/tools/emacs/erlang.el +++ b/lib/tools/emacs/erlang.el @@ -659,24 +659,30 @@ resulting regexp is surrounded by \\_< and \\_>." (eval-and-compile (defconst erlang-guards-regexp (erlang-regexp-opt erlang-guards 'symbols))) - (eval-and-compile (defvar erlang-predefined-types '("any" "arity" + "boolean" "byte" "char" "cons" "deep_string" + "iolist" "maybe_improper_list" + "module" "mfa" "nil" + "neg_integer" "none" "non_neg_integer" "nonempty_list" "nonempty_improper_list" "nonempty_maybe_improper_list" + "no_return" + "pos_integer" "string" + "term" "timeout") "Erlang type specs types")) @@ -885,15 +891,54 @@ files written in other languages than Erlang.") If nil, the inferior shell replaces the window. This is the traditional behaviour.") -(defvar erlang-mode-map nil +(defconst inferior-erlang-use-cmm (boundp 'minor-mode-overriding-map-alist) + "Non-nil means use `compilation-minor-mode' in Erlang shell.") + +(defvar erlang-mode-map + (let ((map (make-sparse-keymap))) + (unless (boundp 'indent-line-function) + (define-key map "\t" 'erlang-indent-command)) + (define-key map ";" 'erlang-electric-semicolon) + (define-key map "," 'erlang-electric-comma) + (define-key map "<" 'erlang-electric-lt) + (define-key map ">" 'erlang-electric-gt) + (define-key map "\C-m" 'erlang-electric-newline) + (if (not (boundp 'delete-key-deletes-forward)) + (define-key map "\177" 'backward-delete-char-untabify) + (define-key map [(backspace)] 'backward-delete-char-untabify)) + ;;(unless (boundp 'fill-paragraph-function) + (define-key map "\M-q" 'erlang-fill-paragraph) + (unless (boundp 'beginning-of-defun-function) + (define-key map "\M-\C-a" 'erlang-beginning-of-function) + (define-key map "\M-\C-e" 'erlang-end-of-function) + (define-key map '(meta control h) 'erlang-mark-function)) ; Xemacs + (define-key map "\M-\t" 'erlang-complete-tag) + (define-key map "\C-c\M-\t" 'tempo-complete-tag) + (define-key map "\M-+" 'erlang-find-next-tag) + (define-key map "\C-c\M-a" 'erlang-beginning-of-clause) + (define-key map "\C-c\M-b" 'tempo-backward-mark) + (define-key map "\C-c\M-e" 'erlang-end-of-clause) + (define-key map "\C-c\M-f" 'tempo-forward-mark) + (define-key map "\C-c\M-h" 'erlang-mark-clause) + (define-key map "\C-c\C-c" 'comment-region) + (define-key map "\C-c\C-j" 'erlang-generate-new-clause) + (define-key map "\C-c\C-k" 'erlang-compile) + (define-key map "\C-c\C-l" 'erlang-compile-display) + (define-key map "\C-c\C-s" 'erlang-show-syntactic-information) + (define-key map "\C-c\C-q" 'erlang-indent-function) + (define-key map "\C-c\C-u" 'erlang-uncomment-region) + (define-key map "\C-c\C-y" 'erlang-clone-arguments) + (define-key map "\C-c\C-a" 'erlang-align-arrows) + (define-key map "\C-c\C-z" 'erlang-shell-display) + (unless inferior-erlang-use-cmm + (define-key map "\C-x`" 'erlang-next-error)) + map) "*Keymap used in Erlang mode.") (defvar erlang-mode-abbrev-table nil "Abbrev table in use in Erlang-mode buffers.") (defvar erlang-mode-syntax-table nil "Syntax table in use in Erlang-mode buffers.") -(defconst inferior-erlang-use-cmm (boundp 'minor-mode-overriding-map-alist) - "Non-nil means use `compilation-minor-mode' in Erlang shell.") (defvar erlang-skel-file "erlang-skels" @@ -1247,7 +1292,7 @@ Other commands: (setq major-mode 'erlang-mode) (setq mode-name "Erlang") (erlang-syntax-table-init) - (erlang-keymap-init) + (use-local-map erlang-mode-map) (erlang-electric-init) (erlang-menu-init) (erlang-mode-variables) @@ -1302,53 +1347,6 @@ Other commands: (set-syntax-table erlang-mode-syntax-table)) -(defun erlang-keymap-init () - (if erlang-mode-map - nil - (setq erlang-mode-map (make-sparse-keymap)) - (erlang-mode-commands erlang-mode-map)) - (use-local-map erlang-mode-map)) - - -(defun erlang-mode-commands (map) - (unless (boundp 'indent-line-function) - (define-key map "\t" 'erlang-indent-command)) - (define-key map ";" 'erlang-electric-semicolon) - (define-key map "," 'erlang-electric-comma) - (define-key map "<" 'erlang-electric-lt) - (define-key map ">" 'erlang-electric-gt) - (define-key map "\C-m" 'erlang-electric-newline) - (if (not (boundp 'delete-key-deletes-forward)) - (define-key map "\177" 'backward-delete-char-untabify) - (define-key map [(backspace)] 'backward-delete-char-untabify)) - ;;(unless (boundp 'fill-paragraph-function) - (define-key map "\M-q" 'erlang-fill-paragraph) - (unless (boundp 'beginning-of-defun-function) - (define-key map "\M-\C-a" 'erlang-beginning-of-function) - (define-key map "\M-\C-e" 'erlang-end-of-function) - (define-key map '(meta control h) 'erlang-mark-function)) ; Xemacs - (define-key map "\M-\t" 'erlang-complete-tag) - (define-key map "\C-c\M-\t" 'tempo-complete-tag) - (define-key map "\M-+" 'erlang-find-next-tag) - (define-key map "\C-c\M-a" 'erlang-beginning-of-clause) - (define-key map "\C-c\M-b" 'tempo-backward-mark) - (define-key map "\C-c\M-e" 'erlang-end-of-clause) - (define-key map "\C-c\M-f" 'tempo-forward-mark) - (define-key map "\C-c\M-h" 'erlang-mark-clause) - (define-key map "\C-c\C-c" 'comment-region) - (define-key map "\C-c\C-j" 'erlang-generate-new-clause) - (define-key map "\C-c\C-k" 'erlang-compile) - (define-key map "\C-c\C-l" 'erlang-compile-display) - (define-key map "\C-c\C-s" 'erlang-show-syntactic-information) - (define-key map "\C-c\C-q" 'erlang-indent-function) - (define-key map "\C-c\C-u" 'erlang-uncomment-region) - (define-key map "\C-c\C-y" 'erlang-clone-arguments) - (define-key map "\C-c\C-a" 'erlang-align-arrows) - (define-key map "\C-c\C-z" 'erlang-shell-display) - (unless inferior-erlang-use-cmm - (define-key map "\C-x`" 'erlang-next-error))) - - (defun erlang-electric-init () ;; Set up electric character functions to work with ;; delsel/pending-del mode. Also, set up text properties for bit @@ -1402,7 +1400,7 @@ Other commands: (set (make-local-variable 'imenu-prev-index-position-function) 'erlang-beginning-of-function) (set (make-local-variable 'imenu-extract-index-name-function) - 'erlang-get-function-name) + 'erlang-get-function-name-and-arity) (set (make-local-variable 'tempo-match-finder) "[^-a-zA-Z0-9_]\\([-a-zA-Z0-9_]*\\)\\=") (set (make-local-variable 'beginning-of-defun-function) @@ -2492,9 +2490,10 @@ Value is list (stack token-start token-type in-what)." ((looking-at "\\(of\\)[^_a-zA-Z0-9]") ;; Must handle separately, try X of -> catch (if (and stack (eq (car (car stack)) 'try)) - (let ((try-column (nth 2 (car stack)))) + (let ((try-column (nth 2 (car stack))) + (try-pos (nth 1 (car stack)))) (erlang-pop stack) - (erlang-push (list 'icr token try-column) stack)))) + (erlang-push (list 'icr try-pos try-column) stack)))) ((looking-at "\\(fun\\)[^_a-zA-Z0-9]") ;; Push a new layer if we are defining a `fun' @@ -2755,7 +2754,7 @@ Return nil if inside string, t if in a comment." ;; ;; `after' should be indented to the same level as the ;; corresponding receive. - (cond ((looking-at "\\(after\\|catch\\|of\\)\\($\\|[^_a-zA-Z0-9]\\)") + (cond ((looking-at "\\(after\\|of\\)\\($\\|[^_a-zA-Z0-9]\\)") (nth 2 stack-top)) ((looking-at "when[^_a-zA-Z0-9]") ;; Handling one when part @@ -2774,7 +2773,7 @@ Return nil if inside string, t if in a comment." ((and (eq (car stack-top) '||) (looking-at "\\(]\\|>>\\)[^_a-zA-Z0-9]")) (nth 2 (car (cdr stack)))) ;; Real indentation, where operators create extra indentation etc. - ((memq (car stack-top) '(-> || begin try)) + ((memq (car stack-top) '(-> || try begin)) (if (looking-at "\\(of\\)[^_a-zA-Z0-9]") (nth 2 stack-top) (goto-char (nth 1 stack-top)) @@ -2803,19 +2802,24 @@ Return nil if inside string, t if in a comment." (erlang-caddr (car stack)) 0)) ((looking-at "catch\\($\\|[^_a-zA-Z0-9]\\)") - (if (or (eq (car stack-top) 'try) - (eq (car (car (cdr stack))) 'icr)) - (progn - (if (eq (car stack-top) '->) - (erlang-pop stack)) - (if stack - (erlang-caddr (car stack)) - 0)) - base)) ;; old catch + ;; Are we in a try + (let ((start (if (eq (car stack-top) '->) + (car (cdr stack)) + stack-top))) + (if (null start) nil + (goto-char (nth 1 start))) + (cond ((looking-at "try\\($\\|[^_a-zA-Z0-9]\\)") + (progn + (if (eq (car stack-top) '->) + (erlang-pop stack)) + (if stack + (erlang-caddr (car stack)) + 0))) + (t (erlang-indent-standard indent-point token base 'nil))))) ;; old catch (t (erlang-indent-standard indent-point token base 'nil) )))) - )) + )) ((eq (car stack-top) 'when) (goto-char (nth 1 stack-top)) (if (looking-at "when\\s *\\($\\|%\\)") @@ -2841,27 +2845,32 @@ Return nil if inside string, t if in a comment." (current-column))) ;; Type and Spec indentation ((eq (car stack-top) '::) - (cond ((null erlang-argument-indent) - ;; indent to next column. - (+ 2 (nth 2 stack-top))) - ((looking-at "::[^_a-zA-Z0-9]") - (nth 2 stack-top)) - (t - (let ((start-alternativ (if (looking-at "|") 2 0))) - (goto-char (nth 1 stack-top)) - (- (cond ((looking-at "::\\s *\\($\\|%\\)") - ;; Line ends with :: - (if (eq (car (car (last stack))) 'spec) + (if (looking-at "}") + ;; Closing record definition with types + ;; pop stack and recurse + (erlang-calculate-stack-indent indent-point + (cons (erlang-pop stack) (cdr state))) + (cond ((null erlang-argument-indent) + ;; indent to next column. + (+ 2 (nth 2 stack-top))) + ((looking-at "::[^_a-zA-Z0-9]") + (nth 2 stack-top)) + (t + (let ((start-alternativ (if (looking-at "|") 2 0))) + (goto-char (nth 1 stack-top)) + (- (cond ((looking-at "::\\s *\\($\\|%\\)") + ;; Line ends with :: + (if (eq (car (car (last stack))) 'spec) (+ (erlang-indent-find-preceding-expr 1) erlang-argument-indent) - (+ (erlang-indent-find-preceding-expr 2) - erlang-argument-indent))) - (t - ;; Indent to the same column as the first - ;; argument. - (goto-char (+ 2 (nth 1 stack-top))) - (skip-chars-forward " \t") - (current-column))) start-alternativ))))) + (+ (erlang-indent-find-preceding-expr 2) + erlang-argument-indent))) + (t + ;; Indent to the same column as the first + ;; argument. + (goto-char (+ 2 (nth 1 stack-top))) + (skip-chars-forward " \t") + (current-column))) start-alternativ)))))) ))) (defun erlang-indent-standard (indent-point token base inside-parenthesis) @@ -2933,10 +2942,16 @@ This assumes that the preceding expression is either simple (skip-chars-backward " \t") ;; Needed to match the colon in "'foo':'bar'". (if (not (memq (preceding-char) '(?# ?:))) - col - (backward-char 1) - (forward-sexp -1) - (current-column))))) + col + ;; Special hack to handle: (note line break) + ;; [#myrecord{ + ;; foo = foo}] + (or + (ignore-errors + (backward-char 1) + (forward-sexp -1) + (current-column)) + col))))) (defun erlang-indent-parenthesis (stack-position) (let ((previous (erlang-indent-find-preceding-expr))) @@ -3505,6 +3520,13 @@ Normally used in conjunction with `erlang-beginning-of-clause', e.g.: res) (error nil))))) +(defun erlang-get-function-name-and-arity () + "Return the name and arity of the function at point, or nil. +The return value is a string of the form \"foo/1\"." + (let ((name (erlang-get-function-name)) + (arity (erlang-get-function-arity))) + (and name arity (format "%s/%d" name arity)))) + (defun erlang-get-function-arguments () "Return arguments of current function, or nil." (if (not (looking-at (eval-when-compile @@ -4901,9 +4923,14 @@ a prompt. When nil, we will wait forever, or until \\[keyboard-quit].") (defvar inferior-erlang-buffer nil "Buffer of last invoked inferior Erlang, or nil.") +;; Enable uniquifying Erlang shell buffers based on directory name. +(eval-after-load "uniquify" + '(add-to-list 'uniquify-list-buffers-directory-modes 'erlang-shell-mode)) + ;;;###autoload -(defun inferior-erlang () +(defun inferior-erlang (&optional command) "Run an inferior Erlang. +With prefix command, prompt for command to start Erlang with. This is just like running Erlang in a normal shell, except that an Emacs buffer is used for input and output. @@ -4917,17 +4944,37 @@ Entry to this mode calls the functions in the variables The following commands imitate the usual Unix interrupt and editing control characters: \\{erlang-shell-mode-map}" - (interactive) + (interactive + (when current-prefix-arg + (list (if (fboundp 'read-shell-command) + ;; `read-shell-command' is a new function in Emacs 23. + (read-shell-command "Erlang command: ") + (read-string "Erlang command: "))))) (require 'comint) - (let ((opts inferior-erlang-machine-options)) - (cond ((eq inferior-erlang-shell-type 'oldshell) - (setq opts (cons "-oldshell" opts))) - ((eq inferior-erlang-shell-type 'newshell) - (setq opts (append '("-newshell" "-env" "TERM" "vt100") opts)))) - (setq inferior-erlang-buffer - (apply 'make-comint - inferior-erlang-process-name inferior-erlang-machine - nil opts))) + (let (cmd opts) + (if command + (setq cmd "sh" + opts (list "-c" command)) + (setq cmd inferior-erlang-machine + opts inferior-erlang-machine-options) + (cond ((eq inferior-erlang-shell-type 'oldshell) + (setq opts (cons "-oldshell" opts))) + ((eq inferior-erlang-shell-type 'newshell) + (setq opts (append '("-newshell" "-env" "TERM" "vt100") opts))))) + + ;; Using create-file-buffer and list-buffers-directory in this way + ;; makes uniquify give each buffer a unique name based on the + ;; directory. + (let ((fake-file-name (expand-file-name inferior-erlang-buffer-name default-directory))) + (setq inferior-erlang-buffer (create-file-buffer fake-file-name)) + (apply 'make-comint-in-buffer + inferior-erlang-process-name + inferior-erlang-buffer + cmd + nil opts) + (with-current-buffer inferior-erlang-buffer + (setq list-buffers-directory fake-file-name)))) + (setq inferior-erlang-process (get-buffer-process inferior-erlang-buffer)) (if (> 21 erlang-emacs-major-version) ; funcalls to avoid compiler warnings @@ -4940,10 +4987,6 @@ editing control characters: (if (and (not (eq system-type 'windows-nt)) (eq inferior-erlang-shell-type 'newshell)) (setq comint-process-echoes t)) - ;; `rename-buffer' takes only one argument in Emacs 18. - (condition-case nil - (rename-buffer inferior-erlang-buffer-name t) - (error (rename-buffer inferior-erlang-buffer-name))) (erlang-shell-mode)) diff --git a/lib/tools/emacs/test.erl.indented b/lib/tools/emacs/test.erl.indented index d0ea4c29cf..2948ccf1b5 100644 --- a/lib/tools/emacs/test.erl.indented +++ b/lib/tools/emacs/test.erl.indented @@ -93,11 +93,27 @@ -type t13() :: maybe_improper_list(integer(), t11()). -type t14() :: [erl_scan:foo() | %% Should be highlighted - non_neg_integer() | nonempty_list() | + term() | + bool() | + byte() | + char() | + non_neg_integer() | nonempty_list() | + pos_integer() | + neg_integer() | + number() | + list() | nonempty_improper_list() | nonempty_maybe_improper_list() | + maybe_improper_list() | string() | iolist() | byte() | + module() | + mfa() | + node() | + timeout() | + no_return() | %% Should not be highlighted nonempty_() | nonlist() | - erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)]. + erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)]. + + -type t15() :: {binary(),<<>>,<<_:34>>,<<_:_*42>>, <<_:3,_:_*14>>,<<>>} | [<<>>|<<_:34>>|<<_:16>>| <<_:3,_:_*1472>>|<<_:19,_:_*14>>| <<_:34>>| @@ -172,6 +188,9 @@ f19 = 3 :: integer()|undefined, f5 = 3 :: undefined|integer()}). +-record(state, { + sequence_number = 1 :: integer() + }). highlighting(X) % Function definitions should be highlighted @@ -493,7 +512,9 @@ indent_try_catch() -> file:close(Xfile) end; indent_try_catch() -> - try foo(bar) of + try + foo(bar) + of X when true andalso kalle -> io:format(stdout, "Parsing file ~s, ", @@ -551,14 +572,57 @@ indent_catch() -> C = catch B + float(43.1), - case catch (X) of + case catch foo(X) of + A -> + B + end, + + case + catch foo(X) + of A -> B end, + + case + foo(X) + of + A -> + catch B, + X + end, + try sune of _ -> foo catch _:_ -> baf - end. + end, + + try + sune + of + _ -> + X = 5, + (catch foo(X)), + X + 10 + catch _:_ -> baf + end, + + try + (catch sune) + of + _ -> + catch foo() %% BUGBUG can't handle catch inside try without parentheses + catch _:_ -> + baf + end, + + try + (catch exit()) + catch + _ -> + catch baf() + end, + ok. indent_binary() -> X = lists:foldr(fun(M) -> @@ -588,3 +652,8 @@ indent_comprehensions() -> true = (X rem 2) >>, ok. + +%% This causes an error in earlier erlang-mode versions. +foo() -> + [#foo{ + foo = foo}]. diff --git a/lib/tools/emacs/test.erl.orig b/lib/tools/emacs/test.erl.orig index 70e97a2e91..1221c5655e 100644 --- a/lib/tools/emacs/test.erl.orig +++ b/lib/tools/emacs/test.erl.orig @@ -93,11 +93,27 @@ -type t13() :: maybe_improper_list(integer(), t11()). -type t14() :: [erl_scan:foo() | %% Should be highlighted - non_neg_integer() | nonempty_list() | + term() | + bool() | + byte() | + char() | + non_neg_integer() | nonempty_list() | + pos_integer() | + neg_integer() | + number() | + list() | nonempty_improper_list() | nonempty_maybe_improper_list() | + maybe_improper_list() | string() | iolist() | byte() | + module() | + mfa() | + node() | + timeout() | + no_return() | %% Should not be highlighted nonempty_() | nonlist() | -erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)]. + erl_scan:bar(34, 92) | t13() | m:f(integer() | <<_:_*16>>)]. + + -type t15() :: {binary(),<<>>,<<_:34>>,<<_:_*42>>, <<_:3,_:_*14>>,<<>>} | [<<>>|<<_:34>>|<<_:16>>| <<_:3,_:_*1472>>|<<_:19,_:_*14>>| <<_:34>>| @@ -172,6 +188,9 @@ f18 :: 1 | 2 | 'undefined', f19 = 3 :: integer()|undefined, f5 = 3 :: undefined|integer()}). +-record(state, { + sequence_number = 1 :: integer() + }). highlighting(X) % Function definitions should be highlighted @@ -493,7 +512,9 @@ indent_try_catch() -> file:close(Xfile) end; indent_try_catch() -> - try foo(bar) of + try + foo(bar) + of X when true andalso kalle -> io:format(stdout, "Parsing file ~s, ", @@ -551,14 +572,57 @@ indent_catch() -> C = catch B + float(43.1), - case catch (X) of + case catch foo(X) of A -> B end, + + case + catch foo(X) + of + A -> + B + end, + + case + foo(X) + of + A -> + catch B, + X + end, + try sune of - _ -> foo - catch _:_ -> baf - end. + _ -> foo + catch _:_ -> baf + end, + + try +sune + of + _ -> + X = 5, + (catch foo(X)), + X + 10 + catch _:_ -> baf + end, + + try + (catch sune) + of + _ -> + catch foo() %% BUGBUG can't handle catch inside try without parentheses + catch _:_ -> + baf + end, + + try +(catch exit()) + catch +_ -> + catch baf() + end, + ok. indent_binary() -> X = lists:foldr(fun(M) -> @@ -588,3 +652,8 @@ Binary2 = << <<X:8>> || <<X:32,_:32>> <= <<0:512>>, true = (X rem 2) >>, ok. + +%% This causes an error in earlier erlang-mode versions. +foo() -> +[#foo{ +foo = foo}]. diff --git a/lib/tools/src/xref_base.erl b/lib/tools/src/xref_base.erl index d0dbf4a2b4..1656899e8f 100644 --- a/lib/tools/src/xref_base.erl +++ b/lib/tools/src/xref_base.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. 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% %% @@ -29,7 +29,7 @@ add_release/2, add_release/3, get_library_path/1, set_library_path/2, set_library_path/3, set_up/1, set_up/2, - q/2, q/3, info/1, info/2, info/3, update/1, update/2, + q/2, q/3, info/1, info/2, info/3, update/1, update/2, forget/1, forget/2, variables/1, variables/2, analyze/2, analyze/3, analysis/1, get_default/2, set_default/3, @@ -38,14 +38,14 @@ -export([format_error/1]). %% The following functions are exported for testing purposes only: --export([do_add_module/4, do_add_application/2, do_add_release/2, +-export([do_add_module/4, do_add_application/2, do_add_release/2, do_remove_module/2]). --import(lists, - [filter/2, flatten/1, foldl/3, keysearch/3, map/2, mapfoldl/3, - member/2, reverse/1, sort/1, usort/1]). +-import(lists, + [filter/2, flatten/1, foldl/3, foreach/2, keysearch/3, map/2, + mapfoldl/3, member/2, reverse/1, sort/1, usort/1]). --import(sofs, +-import(sofs, [constant_function/2, converse/1, difference/2, domain/1, empty_set/0, family/1, family_difference/2, intersection/2, family_projection/2, family_to_relation/1, family_union/1, @@ -103,12 +103,12 @@ delete(State) -> ok end end, - map(Fun, dict:to_list(State#xref.variables)), + foreach(Fun, dict:to_list(State#xref.variables)), ok. add_directory(State, Dir) -> add_directory(State, Dir, []). - + %% -> {ok, Modules, NewState} | Error add_directory(State, Dir, Options) -> ValOptions = option_values([builtins, recurse, verbose, warnings], State), @@ -277,7 +277,7 @@ q(S, Q, Options) when is_atom(Q) -> q(S, atom_to_list(Q), Options); q(S, Q, Options) -> case xref_utils:is_string(Q, 1) of - true -> + true -> case set_up(S, Options) of {ok, S1} -> case xref_compiler:compile(Q, S1#xref.variables) of @@ -336,7 +336,7 @@ forget(State, Variable) when is_atom(Variable) -> forget(State, Variables) -> Vars = State#xref.variables, do_forget(Variables, Vars, Variables, State). - + variables(State) -> variables(State, [user]). @@ -350,9 +350,9 @@ variables(State, Options) -> {ok, NewState} -> {U, P} = do_variables(NewState), R1 = if User -> [{user, U}]; true -> [] end, - R = if - Predef -> [{predefined,P} | R1]; - true -> R1 + R = if + Predef -> [{predefined,P} | R1]; + true -> R1 end, {{ok, R}, NewState}; Error -> @@ -368,7 +368,7 @@ analyze(State, Analysis) -> %% -> {{ok, Answer}, NewState} | {Error, NewState} analyze(State, Analysis, Options) -> case analysis(Analysis, State#xref.mode) of - P when is_list(P) -> + P when is_list(P) -> q(State, P, Options); error -> R = case analysis(Analysis, functions) of @@ -461,7 +461,7 @@ get_default(State, Option) -> %% -> [{Option, Value}] get_default(State) -> - Fun = fun(O) -> V = current_default(State, O), {O, V} end, + Fun = fun(O) -> V = current_default(State, O), {O, V} end, map(Fun, [builtins, recurse, verbose, warnings]). %% -> {ok, NewState} -> Error @@ -478,7 +478,7 @@ set_default(State, Options) -> format_error({error, Module, Error}) -> Module:format_error(Error); format_error({invalid_options, Options}) -> - io_lib:format("Unknown option(s) or invalid option value(s): ~p~n", + io_lib:format("Unknown option(s) or invalid option value(s): ~p~n", [Options]); format_error({invalid_filename, Term}) -> io_lib:format("A file name (a string) was expected: ~p~n", [Term]); @@ -540,7 +540,7 @@ updated_modules(State) -> case xref_utils:file_info(File) of {ok, {_, file, readable, MTime}} when MTime =/= RTime -> [{M,File} | L]; - _Else -> + _Else -> L end end, @@ -591,7 +591,7 @@ do_add_release(Dir, RelName, OB, OV, OW, State) -> case xref_utils:release_directory(Dir, true, "ebin") of {ok, ReleaseDirName, ApplDir, Dirs} -> ApplDirs = xref_utils:select_last_application_version(Dirs), - Release = case RelName of + Release = case RelName of [[]] -> ReleaseDirName; [Name] -> Name end, @@ -615,7 +615,7 @@ do_add_release(S, XRel) -> end. add_rel_appls([ApplDir | ApplDirs], Release, OB, OV, OW, State) -> - {ok, _AppName, NewState} = + {ok, _AppName, NewState} = add_appldir(ApplDir, Release, [[]], OB, OV, OW, State), add_rel_appls(ApplDirs, Release, OB, OV, OW, NewState); add_rel_appls([], [Release], _OB, _OV, _OW, NewState) -> @@ -637,10 +637,10 @@ add_appldir(ApplDir, Release, Name, OB, OV, OW, OldState) -> [[]] -> AppName0; [N] -> N end, - AppInfo = #xref_app{name = AppName, rel_name = Release, + AppInfo = #xref_app{name = AppName, rel_name = Release, vsn = Vsn, dir = Dir}, State1 = do_add_application(OldState, AppInfo), - {ok, _Modules, NewState} = + {ok, _Modules, NewState} = do_add_directory(Dir, [AppName], OB, false, OV, OW, State1), {ok, AppName, NewState}. @@ -662,7 +662,7 @@ do_add_directory(Dir, AppName, Bui, Rec, Ver, War, State) -> ok = is_filename(Dir), {FileNames, Errors, Jams, Unreadable} = xref_utils:scan_directory(Dir, Rec, [?Suffix], [".jam"]), - warnings(War, jam, Jams), + warnings(War, jam, Jams), warnings(War, unreadable, Unreadable), case Errors of [] -> @@ -683,7 +683,7 @@ do_add_a_module(File, AppName, Builtins, Verbose, Warnings, State) -> false -> throw_error({invalid_filename, File}); Splitname -> - do_add_module(Splitname, AppName, Builtins, Verbose, + do_add_module(Splitname, AppName, Builtins, Verbose, Warnings, State) end. @@ -691,7 +691,7 @@ do_add_a_module(File, AppName, Builtins, Verbose, Warnings, State) -> %% Options: verbose, warnings, builtins do_add_module({Dir, Basename}, AppName, Builtins, Verbose, Warnings, State) -> File = filename:join(Dir, Basename), - {ok, M, Bad, NewState} = + {ok, M, Bad, NewState} = do_add_module1(Dir, File, AppName, Builtins, Verbose, Warnings, State), filter(fun({Tag,B}) -> warnings(Warnings, Tag, [[File,B]]) end, Bad), {ok, M, NewState}. @@ -723,7 +723,7 @@ do_add_module1(Dir, File, AppName, Builtins, Verbose, Warnings, State) -> {ok, {_, _, _, Time}} -> Time; Error -> throw(Error) end, - XMod = #xref_mod{name = M, app_name = AppName, dir = Dir, + XMod = #xref_mod{name = M, app_name = AppName, dir = Dir, mtime = T, builtins = Builtins, no_unresolved = NoUnresCalls}, do_add_module(State, XMod, UnresCalls, Data); @@ -736,13 +736,13 @@ abst(File, Builtins, Mode) when Mode =:= functions -> case beam_lib:chunks(File, [abstract_code, exports, attributes]) of {ok, {M,[{abstract_code,NoA},_X,_A]}} when NoA =:= no_abstract_code -> {ok, M, NoA}; - {ok, {M, [{abstract_code, {abstract_v1, Forms}}, + {ok, {M, [{abstract_code, {abstract_v1, Forms}}, {exports,X0}, {attributes,A}]}} -> %% R7. X = xref_utils:fa_to_mfa(X0, M), D = deprecated(A, X, M), xref_reader:module(M, Forms, Builtins, X, D); - {ok, {M, [{abstract_code, {abstract_v2, Forms}}, + {ok, {M, [{abstract_code, {abstract_v2, Forms}}, {exports,X0}, {attributes,A}]}} -> %% R8-R9B. X = xref_utils:fa_to_mfa(X0, M), @@ -769,8 +769,8 @@ abst(File, Builtins, Mode) when Mode =:= modules -> true -> I0; false -> - Fun = fun({M,F,A}) -> - not xref_utils:is_builtin(M, F, A) + Fun = fun({M,F,A}) -> + not xref_utils:is_builtin(M, F, A) end, filter(Fun, I0) end, @@ -790,7 +790,7 @@ mfa_exports(X0, Attributes, M) -> xref_utils:fa_to_mfa(X1, M). adjust_arity(F, A) -> - case xref_utils:is_static_function(F, A) of + case xref_utils:is_static_function(F, A) of true -> A; false -> A - 1 end. @@ -885,7 +885,7 @@ do_add_module(S, M, XMod, Unres0, Data) when S#xref.mode =:= functions -> Unres = domain(UnresCalls), DefinedFuns = domain(DefAt), - {AXC, ALC, Bad1, LPreCAt2, XPreCAt2} = + {AXC, ALC, Bad1, LPreCAt2, XPreCAt2} = extra_edges(AXC1, ALC1, Bad0, DefinedFuns), Bad = map(fun(B) -> {xref_attr, B} end, Bad1), LPreCAt = union(LPreCAt1, LPreCAt2), @@ -904,8 +904,8 @@ do_add_module(S, M, XMod, Unres0, Data) when S#xref.mode =:= functions -> %% {EE, ECallAt} = inter_graph(X, L, LC, XC, LCallAt, XCallAt), Self = self(), - Fun = fun() -> inter_graph(Self, X, L, LC, XC, CallAt) end, - {EE, ECallAt} = + Fun = fun() -> inter_graph(Self, X, L, LC, XC, CallAt) end, + {EE, ECallAt} = xref_utils:subprocess(Fun, [link, {min_heap_size,100000}]), [DefAt2,L2,X2,LCallAt2,XCallAt2,CallAt2,LC2,XC2,EE2,ECallAt2, @@ -977,13 +977,13 @@ extra_edges(CAX, CAL, Bad0, F) -> ALC = restriction(2, restriction(ALC0, F), F), LPreCAt2 = restriction(CAL, ALC), XPreCAt2 = restriction(CAX, AXC), - Bad = Bad0 ++ to_external(difference(AXC0, AXC)) + Bad = Bad0 ++ to_external(difference(AXC0, AXC)) ++ to_external(difference(ALC0, ALC)), {AXC, ALC, Bad, LPreCAt2, XPreCAt2}. no_info(X, L, LC, XC, EE, Unres, NoCalls, NoUnresCalls) -> NoUnres = no_elements(Unres), - [{no_calls, {NoCalls-NoUnresCalls, NoUnresCalls}}, + [{no_calls, {NoCalls-NoUnresCalls, NoUnresCalls}}, {no_function_calls, {no_elements(LC), no_elements(XC)-NoUnres, NoUnres}}, {no_functions, {no_elements(L), no_elements(X)}}, %% Note: this is overwritten in do_set_up(): @@ -1011,10 +1011,10 @@ inter_graph(X, L, LC, XC, CallAt) -> Es = union(LEs, XEs), E1 = to_external(restriction(difference(LC, LEs), XL)), - R0 = xref_utils:xset(reachable(E1, G, []), + R0 = xref_utils:xset(reachable(E1, G, []), [{tspec(func), tspec(fun_edge)}]), true = digraph:delete(G), - + % RL is a set of indirect local calls to exports. RL = restriction(R0, XL), % RX is a set of indirect external calls to exports. @@ -1033,7 +1033,7 @@ inter_graph(X, L, LC, XC, CallAt) -> ?FORMAT("XL=~p~nXEs=~p~nLEs=~p~nE1=~p~nR0=~p~nRL=~p~nRX=~p~nR=~p~n" "EE=~p~nECallAt1=~p~nECallAt2=~p~nECallAt=~p~n~n", - [XL, XEs, LEs, E1, R0, RL, RX, R, EE, + [XL, XEs, LEs, E1, R0, RL, RX, R, EE, ECallAt1, ECallAt2, ECallAt]), {EE, ECallAt}. @@ -1121,7 +1121,7 @@ remove_erase([], D) -> do_add_libraries(Path, Verbose, State) -> message(Verbose, lib_search, []), - {C, E} = xref_utils:list_path(Path, [?Suffix]), + {C, E} = xref_utils:list_path(Path, [?Suffix]), message(Verbose, done, []), MDs = to_external(relation_to_family(relation(C))), %% message(Verbose, lib_check, []), @@ -1160,23 +1160,23 @@ do_set_up(S, VerboseOpt) -> Reply. %% If data has been supplied using add_module/9 (and that is the only -%% sanctioned way), then DefAt, L, X, LCallAt, XCallAt, CallAt, XC, LC, -%% and LU are guaranteed to be functions (with all supplied -%% modules as domain (disregarding unknown modules, that is, modules +%% sanctioned way), then DefAt, L, X, LCallAt, XCallAt, CallAt, XC, LC, +%% and LU are guaranteed to be functions (with all supplied +%% modules as domain (disregarding unknown modules, that is, modules %% not supplied but hosting unknown functions)). %% As a consequence, V and E are also functions. V is defined for unknown %% modules also. %% UU is also a function (thanks to sofs:family_difference/2...). -%% XU on the other hand can be a partial function (that is, not defined +%% XU on the other hand can be a partial function (that is, not defined %% for all modules). U is derived from XU, so U is also partial. %% The inverse variables - LC_1, XC_1, E_1 and EE_1 - are all partial. %% B is also partial. do_set_up(S) when S#xref.mode =:= functions -> ModDictList = dict:to_list(S#xref.modules), - [DefAt0, L, X0, LCallAt, XCallAt, CallAt, LC, XC, LU, + [DefAt0, L, X0, LCallAt, XCallAt, CallAt, LC, XC, LU, EE0, ECallAt, UC, LPredefined, Mod_DF,Mod_DF_1,Mod_DF_2,Mod_DF_3] = make_families(ModDictList, 18), - + {XC_1, XU, XPredefined} = do_set_up_1(XC), LC_1 = user_family(union_of_family(LC)), E_1 = family_union(XC_1, LC_1), @@ -1206,7 +1206,7 @@ do_set_up(S) when S#xref.mode =:= functions -> AM = domain(F1), %% Undef is the union of U0 and Lib: - {Undef, U0, Lib, Lib_DF, Lib_DF_1, Lib_DF_2, Lib_DF_3} = + {Undef, U0, Lib, Lib_DF, Lib_DF_1, Lib_DF_2, Lib_DF_3} = make_libs(XU, F1, AM, S#xref.library_path, S#xref.libraries), {B, U} = make_builtins(U0), X1_B = family_union(X1, B), @@ -1228,22 +1228,22 @@ do_set_up(S) when S#xref.mode =:= functions -> %% way to discard calls to local functions in other modules. EE_conv = converse(union_of_family(EE0)), EE_exported = restriction(EE_conv, union_of_family(X)), - EE_local = + EE_local = specification({external, fun({{M1,_,_},{M2,_,_}}) -> M1 =:= M2 end}, EE_conv), EE_0 = converse(union(EE_local, EE_exported)), EE_1 = user_family(EE_0), - EE1 = partition_family({external, fun({{M1,_,_}, _MFA2}) -> M1 end}, + EE1 = partition_family({external, fun({{M1,_,_}, _MFA2}) -> M1 end}, EE_0), %% Make sure EE is defined for all modules: EE = family_union(family_difference(EE0, EE0), EE1), - IFun = - fun({Mod,EE_M}, XMods) -> - IMFun = + IFun = + fun({Mod,EE_M}, XMods) -> + IMFun = fun(XrefMod) -> - [NoCalls, NoFunctionCalls, + [NoCalls, NoFunctionCalls, NoFunctions, _NoInter] = XrefMod#xref_mod.info, - NewInfo = [NoCalls, NoFunctionCalls, NoFunctions, + NewInfo = [NoCalls, NoFunctionCalls, NoFunctions, {no_inter_function_calls,length(EE_M)}], XrefMod#xref_mod{info = NewInfo} end, @@ -1274,11 +1274,11 @@ do_set_up(S) when S#xref.mode =:= functions -> finish_set_up(S1, Vs); do_set_up(S) when S#xref.mode =:= modules -> ModDictList = dict:to_list(S#xref.modules), - [X0, I0, Mod_DF, Mod_DF_1, Mod_DF_2, Mod_DF_3] = + [X0, I0, Mod_DF, Mod_DF_1, Mod_DF_2, Mod_DF_3] = make_families(ModDictList, 7), I = union_of_family(I0), AM = domain(X0), - + {XU, Predefined} = make_predefined(I, AM), %% Add "hidden" functions to the exports. X1 = family_union(X0, Predefined), @@ -1288,8 +1288,8 @@ do_set_up(S) when S#xref.mode =:= modules -> M2A = make_M2A(ModDictList), {A2R,A} = make_A2R(S#xref.applications), R = set(dict:fetch_keys(S#xref.releases)), - - ME = projection({external, fun({M1,{M2,_F2,_A2}}) -> {M1,M2} end}, + + ME = projection({external, fun({M1,{M2,_F2,_A2}}) -> {M1,M2} end}, family_to_relation(I0)), ME2AE = multiple_relative_product({M2A, M2A}, ME), @@ -1298,7 +1298,7 @@ do_set_up(S) when S#xref.mode =:= modules -> RE = range(AE2RE), %% Undef is the union of U0 and Lib: - {_Undef, U0, Lib, Lib_DF, Lib_DF_1, Lib_DF_2, Lib_DF_3} = + {_Undef, U0, Lib, Lib_DF, Lib_DF_1, Lib_DF_2, Lib_DF_3} = make_libs(XU, X1, AM, S#xref.library_path, S#xref.libraries), {B, U} = make_builtins(U0), X1_B = family_union(X1, B), @@ -1312,7 +1312,7 @@ do_set_up(S) when S#xref.mode =:= modules -> X = family_union(X1, Lib), Empty = empty_set(), - Vs = [{'X',X},{'U',U},{'B',B},{'XU',XU},{v,V}, + Vs = [{'X',X},{'U',U},{'B',B},{'XU',XU},{v,V}, {e,{Empty,Empty}}, {'M',M},{'A',A},{'R',R}, {'AM',AM},{'UM',UM},{'LM',LM}, @@ -1328,10 +1328,10 @@ finish_set_up(S, Vs) -> S1 = S#xref{variables = T}, %% io:format("~p <= state <= ~p~n", [pack:lsize(S), pack:usize(S)]), {ok, S1}. - + do_finish_set_up([{Key, Value} | Vs], T) -> {Type, OType} = var_type(Key), - Val = #xref_var{name = Key, value = Value, vtype = predef, + Val = #xref_var{name = Key, value = Value, vtype = predef, otype = OType, type = Type}, T1 = dict:store(Key, Val, T), do_finish_set_up(Vs, T1); @@ -1362,15 +1362,15 @@ var_type('EE') -> {function, edge}; var_type('LC') -> {function, edge}; var_type('UC') -> {function, edge}; var_type('XC') -> {function, edge}; -var_type('AE') -> {application, edge}; -var_type('ME') -> {module, edge}; +var_type('AE') -> {application, edge}; +var_type('ME') -> {module, edge}; var_type('RE') -> {release, edge}; var_type(_) -> {foo, bar}. make_families(ModDictList, N) -> Fun1 = fun({_,XMod}) -> XMod#xref_mod.data end, Ss = from_sets(map(Fun1, ModDictList)), - %% io:format("~n~p <= module data <= ~p~n", + %% io:format("~n~p <= module data <= ~p~n", %% [pack:lsize(Ss), pack:usize(Ss)]), make_fams(N, Ss, []). @@ -1389,7 +1389,7 @@ make_M2A(ModDictList) -> make_A2R(ApplDict) -> AppDict = dict:to_list(ApplDict), Fun = fun({A,XApp}) -> {A, XApp#xref_app.rel_name} end, - Appl0 = family(map(Fun, AppDict)), + Appl0 = family(map(Fun, AppDict)), AllApps = domain(Appl0), Appl = family_to_relation(Appl0), {Appl, AllApps}. @@ -1445,13 +1445,13 @@ make_libs(XU, F, AM, LibPath, LibDict) -> false -> Libraries = dict:to_list(LibDict), Lb = restriction(a_function(Libraries), UM), - MFun = fun({M,XLib}) -> + MFun = fun({M,XLib}) -> #xref_lib{dir = Dir} = XLib, xref_utils:module_filename(Dir, M) end, map(MFun, to_external(Lb)) end, - Fun = fun(FileName, Deprs) -> + Fun = fun(FileName, Deprs) -> case beam_lib:chunks(FileName, [exports, attributes]) of {ok, {M, [{exports,X}, {attributes,A}]}} -> Exports = mfa_exports(X, A, M), @@ -1496,14 +1496,14 @@ user_family(R) -> partition_family({external, fun({_MFA1, {M2,_,_}}) -> M2 end}, R). do_variables(State) -> - Fun = fun({Name, #xref_var{vtype = user}}, {P,U}) -> + Fun = fun({Name, #xref_var{vtype = user}}, {P,U}) -> {P,[Name | U]}; - ({Name, #xref_var{vtype = predef}}, A={P,U}) -> + ({Name, #xref_var{vtype = predef}}, A={P,U}) -> case atom_to_list(Name) of [H|_] when H>= $a, H=<$z -> A; _Else -> {[Name | P], U} end; - ({{tmp, V}, _}, A) -> + ({{tmp, V}, _}, A) -> io:format("Bug in ~p: temporary ~p~n", [?MODULE, V]), A; (_V, A) -> A end, @@ -1565,7 +1565,7 @@ do_info(S, libraries) -> map(fun({_L,XLib}) -> lib_info(XLib) end, D); do_info(_S, I) -> error({no_such_info, I}). - + do_info(S, Type, E) when is_atom(E) -> do_info(S, Type, [E]); do_info(S, modules, Modules0) when is_list(Modules0) -> @@ -1598,7 +1598,7 @@ find_info([E | Es], Dict, Error) -> {ok, X} -> [X | find_info(Es, Dict, Error)] end; -find_info([], _Dict, _Error) -> +find_info([], _Dict, _Error) -> []. %% -> {[{AppName, RelName}], [{RelName, XApp}]} @@ -1618,7 +1618,7 @@ rel_apps(S) -> rel_apps_sums(AR, RRA0, S) -> AppMods = app_mods(S), % [{AppName, XMod}] RRA1 = relation_to_family(relation(RRA0)), - RRA = inverse(substitution(1, RRA1)), + RRA = inverse(substitution(1, RRA1)), %% RRA is [{RelName,{RelName,[XApp]}}] RelMods = relative_product1(relation(AR), relation(AppMods)), RelAppsMods = relative_product1(RRA, RelMods), @@ -1630,7 +1630,7 @@ rel_apps_sums(AR, RRA0, S) -> %% -> [{AppName, XMod}] app_mods(S) -> D = sort(dict:to_list(S#xref.modules)), - Fun = fun({_M,XMod}, Acc) -> + Fun = fun({_M,XMod}, Acc) -> case XMod#xref_mod.app_name of [] -> Acc; [AppName] -> [{AppName, XMod} | Acc] @@ -1639,7 +1639,7 @@ app_mods(S) -> foldl(Fun, [], D). mod_info(XMod) -> - #xref_mod{name = M, app_name = AppName, builtins = BuiltIns, + #xref_mod{name = M, app_name = AppName, builtins = BuiltIns, dir = Dir, info = Info} = XMod, App = sup_info(AppName), {M, [{application, App}, {builtins, BuiltIns}, {directory, Dir} | Info]}. @@ -1649,7 +1649,7 @@ app_info({AppName, ModSums}, S) -> #xref_app{rel_name = RelName, vsn = Vsn, dir = Dir} = XApp, Release = sup_info(RelName), {AppName, [{directory,Dir}, {release, Release}, {version,Vsn} | ModSums]}. - + rel_info({{RelName, XApps}, ModSums}, S) -> NoApps = length(XApps), XRel = dict:fetch(RelName, S#xref.releases), @@ -1678,16 +1678,16 @@ no_sum(S, L) when S#xref.mode =:= modules -> [{no_analyzed_modules, length(L)}]. no_sum([XMod | D], C0, UC0, LC0, XC0, UFC0, L0, X0, EV0, NoM) -> - [{no_calls, {C,UC}}, + [{no_calls, {C,UC}}, {no_function_calls, {LC,XC,UFC}}, {no_functions, {L,X}}, {no_inter_function_calls, EV}] = XMod#xref_mod.info, no_sum(D, C0+C, UC0+UC, LC0+LC, XC0+XC, UFC0+UFC, L0+L, X0+X, EV0+EV, NoM); no_sum([], C, UC, LC, XC, UFC, L, X, EV, NoM) -> [{no_analyzed_modules, NoM}, - {no_calls, {C,UC}}, + {no_calls, {C,UC}}, {no_function_calls, {LC,XC,UFC}}, - {no_functions, {L,X}}, + {no_functions, {L,X}}, {no_inter_function_calls, EV}]. %% -> ok | throw(Error) @@ -1712,20 +1712,20 @@ warnings(Flag, Message, [F | Fs]) -> %% pack(term()) -> term() %% %% The identify function. The returned term does not use more heap -%% than the given term. Tuples that are equal (=:=/2) are made +%% than the given term. Tuples that are equal (=:=/2) are made %% "the same". %% %% The process dictionary is used because it seems to be faster than %% anything else right now... %% %pack(T) -> T; -pack(T) -> +pack(T) -> PD = erase(), NT = pack1(T), %% true = T =:= NT, %% io:format("erasing ~p elements...~n", [length(erase())]), erase(), % wasting heap (and time)... - map(fun({K,V}) -> put(K, V) end, PD), + foreach(fun({K,V}) -> put(K, V) end, PD), NT. pack1(C) when not is_tuple(C), not is_list(C) -> diff --git a/lib/tools/src/xref_compiler.erl b/lib/tools/src/xref_compiler.erl index 67ac8c617d..c80eb0e669 100644 --- a/lib/tools/src/xref_compiler.erl +++ b/lib/tools/src/xref_compiler.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. 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% %% @@ -37,15 +37,15 @@ -export([format_error/1]). --import(lists, +-import(lists, [concat/1, foldl/3, nthtail/2, reverse/1, sort/1, sublist/2]). -import(sofs, [composite/2, difference/2, empty_set/0, from_term/1, intersection/2, is_empty_set/1, multiple_relative_product/2, projection/2, relation/1, relation_to_family/1, - restriction/2, substitution/2, to_external/1, union/2, - union_of_family/1]). + restriction/2, specification/2, substitution/2, + to_external/1, union/2, union_of_family/1]). %% %% Exported functions @@ -75,7 +75,7 @@ compile(Chars, Table) -> {error, Info, Line} -> error({parse_error, Line, Info}) end. - + format_error({error, Module, Error}) -> Module:format_error(Error); format_error({parse_error, Line, Error}) -> @@ -115,7 +115,7 @@ statements([Stmt={assign, VarType, Name, E} | Stmts0], Table, L, UV) -> throw_error({variable_reassigned, xref_parser:t2s(Stmt)}); error -> {Type, OType, NewE} = t_expr(E, Table), - Val = #xref_var{name = Name, vtype = VarType, + Val = #xref_var{name = Name, vtype = VarType, otype = OType, type = Type}, NewTable = dict:store(Name, Val, Table), Stmts = if Stmts0 =:= [] -> [{variable, Name}]; true -> Stmts0 end, @@ -128,9 +128,9 @@ statements([Expr], Table, L, UV) -> E1 = un_familiarize(Type, OType, NewE), NE = case {Type, OType} of %% Edges with empty sets of line numbers are removed. - {{line, _}, edge} -> + {{line, _}, edge} -> {relation_to_family, E1}; - {_Type, edge_closure} -> + {_Type, edge_closure} -> %% Fake a closure usage, just to make sure it is destroyed. E2 = {fun graph_access/2, E1, E1}, {fun(_E) -> 'closure()' end, E2}; @@ -163,7 +163,7 @@ t_expr(E, Table) -> %%% Constant = atom() | {atom(), atom()} | MFA | {MFA, MFA} %%% Call = atom() % function in the sofs module %%% | fun() -%%% Type = {line, LineType} | function | module | application | release +%%% Type = {line, LineType} | function | module | application | release %%% | number %%% LineType = line | local_call | external_call | export_call | all_line_call %%% VarType = predef | user | tmp @@ -182,7 +182,7 @@ check_expr({variable, Name}, Table) -> case dict:find(Name, Table) of {ok, #xref_var{vtype = VarType, otype = OType, type = Type}} -> V0 = {variable, {VarType, Name}}, - V = case {VarType, Type, OType} of + V = case {VarType, Type, OType} of {predef, release, _} -> V0; {predef, application, _} -> V0; {predef, module, _} -> V0; @@ -212,7 +212,7 @@ check_expr(Expr={set, SOp, E}, Table) -> {edge_set, domain} -> vertex_set; {edge_set, weak} -> edge_set; {edge_set, strict} -> edge_set; - _ -> + _ -> throw_error({type_error, xref_parser:t2s(Expr)}) end, Op = set_op(SOp), @@ -223,10 +223,10 @@ check_expr(Expr={graph, Op, E}, Table) -> case Type of {line, _LineType} -> throw_error({type_error, xref_parser:t2s(Expr)}); - _Else -> + _Else -> ok end, - OType = + OType = case {NOType, Op} of {edge, components} -> vertex_set; {edge, condensation} -> edge_set; @@ -237,7 +237,7 @@ check_expr(Expr={graph, Op, E}, Table) -> %% Neither need nor want these ones: %% {edge_set, closure} -> edge_set_closure; %% {edge_set, components} -> vertex_set_set; - _ -> + _ -> throw_error({type_error, xref_parser:t2s(Expr)}) end, E2 = {convert, NOType, edge_closure, E1}, @@ -271,10 +271,10 @@ check_expr(Expr={set, SOp, E1, E2}, Table) -> number -> {expr, number, number, {call, ari_op(SOp), NE1, NE2}}; _Else -> % set - {Type, NewE1, NewE2} = + {Type, NewE1, NewE2} = case {type_ord(Type1), type_ord(Type2)} of {T1, T2} when T1 =:= T2 -> - %% Example: if Type1 = {line, line} and + %% Example: if Type1 = {line, line} and %% Type2 = {line, export_line}, then this is not %% correct, but works: {Type1, NE1, NE2}; @@ -296,7 +296,7 @@ check_expr(Expr={restr, ROp, E1, E2}, Table) -> throw_error({type_error, xref_parser:t2s(Expr)}); {_Type1, {line, _LineType2}} -> throw_error({type_error, xref_parser:t2s(Expr)}); - _ -> + _ -> ok end, case {OType1, OType2} of @@ -307,14 +307,14 @@ check_expr(Expr={restr, ROp, E1, E2}, Table) -> {edge, vertex} -> restriction(ROp, E1, Type1, NE1, Type2, NE2); {edge_closure, vertex} when ROp =:= '|||' -> - {expr, _, _, R1} = + {expr, _, _, R1} = closure_restriction('|', Type1, Type2, OType2, NE1, NE2), - {expr, _, _, R2} = + {expr, _, _, R2} = closure_restriction('||', Type1, Type2, OType2, NE1, NE2), {expr, Type1, edge, {call, intersection, R1, R2}}; - {edge_closure, vertex} -> + {edge_closure, vertex} -> closure_restriction(ROp, Type1, Type2, OType2, NE1, NE2); - _ -> + _ -> throw_error({type_error, xref_parser:t2s(Expr)}) end; check_expr(Expr={path, E1, E2}, Table) -> @@ -330,7 +330,7 @@ check_expr(Expr={path, E1, E2}, Table) -> end, E2b = {convert, OType2, Type2, Type1, E2a}, {OType1, NE1} = path_arg(OType1a, E1a), - NE2 = case {OType1, OType2} of + NE2 = case {OType1, OType2} of {path, edge} -> {convert, OType2, edge_closure, E2b}; {path, edge_closure} when Type1 =:= Type2 -> E2b; _ -> throw_error({type_error, xref_parser:t2s(Expr)}) @@ -347,7 +347,7 @@ check_expr({regexpr, RExpr, Type0}, _Table) -> release -> 'R' end, Var = {variable, {predef, V}}, - Call = {call, fun(E, V2) -> xref_utils:regexpr(E, V2) end, + Call = {call, fun(E, V2) -> xref_utils:regexpr(E, V2) end, {constants, RExpr}, Var}, {expr, Type, vertex, Call}; check_expr(C={constant, _Type, _OType, _C}, Table) -> @@ -368,15 +368,15 @@ check_conversion(OType, Type1, Type2, Expr) -> end. %% Allowed conversions. -conversions(_OType, {line, LineType}, {line, LineType}) -> ok; +conversions(_OType, {line, LineType}, {line, LineType}) -> ok; conversions(edge, {line, _}, {line, all_line_call}) -> ok; -conversions(edge, From, {line, Line}) +conversions(edge, From, {line, Line}) when is_atom(From), Line =/= all_line_call -> ok; conversions(vertex, From, {line, line}) when is_atom(From) -> ok; conversions(vertex, From, To) when is_atom(From), is_atom(To) -> ok; conversions(edge, From, To) when is_atom(From), is_atom(To) -> ok; %% "Extra": -conversions(edge, {line, Line}, To) +conversions(edge, {line, Line}, To) when is_atom(To), Line =/= all_line_call -> ok; conversions(vertex, {line, line}, To) when is_atom(To) -> ok; conversions(_OType, _From, _To) -> not_ok. @@ -399,7 +399,7 @@ ari_op(difference) -> fun(X, Y) -> X - Y end. restriction(ROp, E1, Type1, NE1, Type2, NE2) -> {Column, _} = restr_op(ROp), - case NE1 of + case NE1 of {call, union_of_family, _E} when ROp =:= '|' -> restriction(Column, Type1, E1, Type2, NE2); {call, union_of_family, _E} when ROp =:= '||' -> @@ -455,8 +455,8 @@ check_constants(Cs=[C={constant, Type0, OType, _Con} | Cs1], Table) -> E = function_vertices_to_family(Type, OType, {constants, S}), {expr, Type, OType, E}; [{Type1, [C1|_]}, {Type2, [C2|_]} | _] -> - throw_error({type_mismatch, - make_vertex(Type1, C1), + throw_error({type_mismatch, + make_vertex(Type1, C1), make_vertex(Type2, C2)}) end. @@ -467,7 +467,7 @@ check_mix([C={constant, Type, OType, _Con} | Cs], Type0, OType, _C0) check_mix(Cs, Type, OType, C); check_mix([C | _], _Type0, _OType0, C0) -> throw_error({type_mismatch, xref_parser:t2s(C0), xref_parser:t2s(C)}); -check_mix([], _Type0, _OType0, _C0) -> +check_mix([], _Type0, _OType0, _C0) -> ok. split(Types, Cs, Table) -> @@ -478,11 +478,11 @@ split([Type | Types], Vs, AllSoFar, _Type, Table, L) -> S0 = known_vertices(Type, Vs, Table), S = difference(S0, AllSoFar), case is_empty_set(S) of - true -> + true -> split(Types, Vs, AllSoFar, Type, Table, L); - false -> + false -> All = union(AllSoFar, S0), - split(Types, Vs, All, Type, Table, + split(Types, Vs, All, Type, Table, [{Type, to_external(S)} | L]) end; split([], Vs, All, Type, _Table, L) -> @@ -491,7 +491,7 @@ split([], Vs, All, Type, _Table, L) -> [C|_] -> throw_error({unknown_constant, make_vertex(Type, C)}) end. -make_vertex(Type, C) -> +make_vertex(Type, C) -> xref_parser:t2s({constant, Type, vertex, C}). constant_vertices([{constant, _Type, edge, {A,B}} | Cs], L) -> @@ -504,7 +504,7 @@ constant_vertices([], L) -> known_vertices('Fun', Cs, T) -> M = projection(1, Cs), F = union_of_family(restriction(fetch_value(v, T), M)), - intersection(Cs, F); + union(bifs(Cs), intersection(Cs, F)); known_vertices('Mod', Cs, T) -> intersection(Cs, fetch_value('M', T)); known_vertices('App', Cs, T) -> @@ -512,6 +512,11 @@ known_vertices('App', Cs, T) -> known_vertices('Rel', Cs, T) -> intersection(Cs, fetch_value('R', T)). +bifs(Cs) -> + specification({external, + fun({M,F,A}) -> xref_utils:is_builtin(M, F, A) end}, + Cs). + function_vertices_to_family(function, vertex, E) -> {call, partition_family, 1, E}; function_vertices_to_family(_Type, _OType, E) -> @@ -567,11 +572,11 @@ convert(E, OType, FromType, ToType) -> general(_ObjectType, FromType, ToType, X) when FromType =:= ToType -> X; -general(edge, {line, _LineType}, ToType, LEs) -> +general(edge, {line, _LineType}, ToType, LEs) -> VEs = {projection, ?Q({external, fun({V1V2,_Ls}) -> V1V2 end}), LEs}, general(edge, function, ToType, VEs); general(edge, function, ToType, VEs) -> - MEs = {projection, + MEs = {projection, ?Q({external, fun({{M1,_,_},{M2,_,_}}) -> {M1,M2} end}), VEs}, general(edge, module, ToType, MEs); @@ -580,7 +585,7 @@ general(edge, module, ToType, MEs) -> general(edge, application, ToType, AEs); general(edge, application, release, AEs) -> {image, {get, ae}, AEs}; -general(vertex, {line, _LineType}, ToType, L) -> +general(vertex, {line, _LineType}, ToType, L) -> V = {partition_family, ?Q(1), {domain, L}}, general(vertex, function, ToType, V); general(vertex, function, ToType, V) -> @@ -595,18 +600,18 @@ general(vertex, application, release, A) -> special(_ObjectType, FromType, ToType, X) when FromType =:= ToType -> X; special(edge, {line, _LineType}, {line, all_line_call}, Calls) -> - {put, ?T(mods), - {projection, - ?Q({external, fun({{{M1,_,_},{M2,_,_}},_}) -> {M1,M2} end}), + {put, ?T(mods), + {projection, + ?Q({external, fun({{{M1,_,_},{M2,_,_}},_}) -> {M1,M2} end}), Calls}, - {put, ?T(def_at), + {put, ?T(def_at), {union, {image, {get, def_at}, - {union, {domain, {get, ?T(mods)}}, + {union, {domain, {get, ?T(mods)}}, {range, {get, ?T(mods)}}}}}, {fun funs_to_lines/2, {get, ?T(def_at)}, Calls}}}; special(edge, function, {line, LineType}, VEs) -> - Var = if + Var = if LineType =:= line -> call_at; LineType =:= export_call -> e_call_at; LineType =:= local_call -> l_call_at; @@ -615,9 +620,9 @@ special(edge, function, {line, LineType}, VEs) -> line_edges(VEs, Var); special(edge, module, ToType, MEs) -> VEs = {image, - {projection, + {projection, ?Q({external, fun(FE={{M1,_,_},{M2,_,_}}) -> {{M1,M2},FE} end}), - {union, + {union, {image, {get, e}, {projection, ?Q({external, fun({M1,_M2}) -> M1 end}), MEs}}}}, MEs}, @@ -629,7 +634,7 @@ special(edge, release, ToType, REs) -> AEs = {inverse_image, {get, ae}, REs}, special(edge, application, ToType, AEs); special(vertex, function, {line, _LineType}, V) -> - {restriction, + {restriction, {union_of_family, {restriction, {get, def_at}, {domain, V}}}, {union_of_family, V}}; special(vertex, module, ToType, M) -> @@ -643,15 +648,15 @@ special(vertex, release, ToType, R) -> special(vertex, application, ToType, A). line_edges(VEs, CallAt) -> - {put, ?T(ves), VEs, - {put, ?T(m1), - {projection, ?Q({external, fun({{M1,_,_},_}) -> M1 end}), + {put, ?T(ves), VEs, + {put, ?T(m1), + {projection, ?Q({external, fun({{M1,_,_},_}) -> M1 end}), {get, ?T(ves)}}, {image, {projection, ?Q({external, fun(C={VV,_L}) -> {VV,C} end}), {union, {image, {get, CallAt}, {get, ?T(m1)}}}}, {get, ?T(ves)}}}}. -%% {(((v1,l1),(v2,l2)),l) : +%% {(((v1,l1),(v2,l2)),l) : %% (v1,l1) in DefAt and (v2,l2) in DefAt and ((v1,v2),L) in CallAt} funs_to_lines(DefAt, CallAt) -> T1 = multiple_relative_product({DefAt, DefAt}, projection(1, CallAt)), @@ -765,7 +770,7 @@ save_vars([], _D, Vs, UVs, L) -> %% Traverses the expression again, this time using more or less the %% inverse of the table created by find_nodes. The first time a node -%% is visited, its children are traversed, the following times a +%% is visited, its children are traversed, the following times a %% get instructions are inserted (using the saved value). make_instructions(N, UserVars, D) -> {D1, Is0} = make_instrs(N, D, []), @@ -777,9 +782,9 @@ make_instructions(N, UserVars, D) -> make_more_instrs([UV | UVs], D, Is) -> case dict:find(UV, D) of - error -> + error -> make_more_instrs(UVs, D, Is); - _Else -> + _Else -> {ND, NIs} = make_instrs(UV, D, Is), make_more_instrs(UVs, ND, [pop | NIs]) end; @@ -844,17 +849,17 @@ evaluate([{quote, Val} | P], T, S) -> evaluate(P, T, [Val | S]); evaluate([{get, Var} | P], T, S) when is_atom(Var) -> % predefined Value = fetch_value(Var, T), - Val = case Value of + Val = case Value of {R, _} -> R; % relation _ -> Value % simple set end, - evaluate(P, T, [Val | S]); + evaluate(P, T, [Val | S]); evaluate([{get, {inverse, Var}} | P], T, S) -> % predefined, inverse {_, R} = fetch_value(Var, T), - evaluate(P, T, [R | S]); + evaluate(P, T, [R | S]); evaluate([{get, {user, Var}} | P], T, S) -> Val = fetch_value(Var, T), - evaluate(P, T, [Val | S]); + evaluate(P, T, [Val | S]); evaluate([{get, Var} | P], T, S) -> % tmp evaluate(P, T, [dict:fetch(Var, T) | S]); evaluate([{save, Var={tmp, _}} | P], T, S=[Val | _]) -> @@ -862,7 +867,7 @@ evaluate([{save, Var={tmp, _}} | P], T, S=[Val | _]) -> evaluate(P, dict:store(Var, Val, T1), S); evaluate([{save, {user, Name}} | P], T, S=[Val | _]) -> #xref_var{vtype = user, otype = OType, type = Type} = dict:fetch(Name, T), - NewVar = #xref_var{name = Name, value = Val, + NewVar = #xref_var{name = Name, value = Val, vtype = user, otype = OType, type = Type}, T1 = update_graph_counter(Val, +1, T), NT = dict:store(Name, NewVar, T1), @@ -889,7 +894,7 @@ update_graph_counter(Value, Inc, T) -> error when Inc =:= 1 -> dict:store(Value, 1, T) end; - _EXIT -> + _EXIT -> T end. diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl index db755c31d8..d22f0df164 100644 --- a/lib/tools/src/xref_reader.erl +++ b/lib/tools/src/xref_reader.erl @@ -1,19 +1,19 @@ %% %% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2000-2009. All Rights Reserved. -%% +%% +%% Copyright Ericsson AB 2000-2010. 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% %% -module(xref_reader). @@ -22,7 +22,7 @@ -import(lists, [keysearch/3, member/2, reverse/1]). --record(xrefr, +-record(xrefr, {module=[], function=[], def_at=[], @@ -59,15 +59,15 @@ module(Module, Forms, CollectBuiltins, X, DF) -> Attrs = [{Attr,V} || {attribute,_Line,Attr,V} <- Forms], IsAbstract = xref_utils:is_abstract_module(Attrs), - S = #xrefr{module = Module, builtins_too = CollectBuiltins, + S = #xrefr{module = Module, builtins_too = CollectBuiltins, is_abstr = IsAbstract, x = X, df = DF}, forms(Forms, S). forms([F | Fs], S) -> S1 = form(F, S), forms(Fs, S1); -forms([], S) -> - #xrefr{module = M, def_at = DefAt, +forms([], S) -> + #xrefr{module = M, def_at = DefAt, l_call_at = LCallAt, x_call_at = XCallAt, el = LC, ex = XC, x = X, df = Depr, lattrs = AL, xattrs = AX, battrs = B, unresolved = U} = S, @@ -75,7 +75,7 @@ forms([], S) -> {ok, M, {DefAt, LCallAt, XCallAt, LC, XC, X, Attrs, Depr}, U}. form({attribute, Line, xref, Calls}, S) -> % experimental - #xrefr{module = M, function = Fun, + #xrefr{module = M, function = Fun, lattrs = L, xattrs = X, battrs = B} = S, attr(Calls, Line, M, Fun, L, X, B, S); form({attribute, _Line, _Attr, _Val}, S) -> @@ -110,12 +110,12 @@ clauses([{clause, _Line, _H, G, B} | Cs], FunVars, Matches, S) -> S2 = expr(B, S1), S3 = S2#xrefr{funvars = FunVars, matches = Matches}, clauses(Cs, S3); -clauses([], _FunVars, _Matches, S) -> +clauses([], _FunVars, _Matches, S) -> S. attr([E={From, To} | As], Ln, M, Fun, AL, AX, B, S) -> case mfa(From, M) of - {_, _, MFA} when MFA =:= Fun; [] =:= Fun -> + {_, _, MFA} when MFA =:= Fun; [] =:= Fun -> attr(From, To, Ln, M, Fun, AL, AX, B, S, As, E); {_, _, _} -> attr(As, Ln, M, Fun, AL, AX, [E | B], S); @@ -164,7 +164,7 @@ expr({call, Line, %% Added in R10B-6. M:F/A. expr({'fun', Line, {function, Mod, Fun, Arity}}, S); expr({'fun', Line, {function, Mod, Name, Arity}}, S) -> - %% Added in R10B-6. M:F/A. + %% Added in R10B-6. M:F/A. As = lists:duplicate(Arity, {atom, Line, foo}), external_call(Mod, Name, As, Line, false, S); expr({'fun', Line, {function, Name, Arity}, _Extra}, S) -> @@ -183,7 +183,7 @@ expr({call, Line, {remote, _Line, Mod, Name}, As}, S) -> expr({call, Line, F, As}, S) -> external_call(erlang, apply, [F, list2term(As)], Line, true, S); expr({match, _Line, {var,_,Var}, {'fun', _, {clauses, Cs}, _Extra}}, S) -> - %% This is what is needed in R7 to avoid warnings for the functions + %% This is what is needed in R7 to avoid warnings for the functions %% that are passed around by the "expansion" of list comprehension. S1 = S#xrefr{funvars = [Var | S#xrefr.funvars]}, clauses(Cs, S1); @@ -192,6 +192,14 @@ expr({match, _Line, {var,_,Var}, E}, S) -> %% Args = [A,B], apply(m, f, Args) S1 = S#xrefr{matches = [{Var, E} | S#xrefr.matches]}, expr(E, S1); +expr({op, _Line, 'orelse', Op1, Op2}, S) -> + expr([Op1, Op2], S); +expr({op, _Line, 'andalso', Op1, Op2}, S) -> + expr([Op1, Op2], S); +expr({op, Line, Op, Operand1, Operand2}, S) -> + external_call(erlang, Op, [Operand1, Operand2], Line, false, S); +expr({op, Line, Op, Operand}, S) -> + external_call(erlang, Op, [Operand], Line, false, S); expr(T, S) when is_tuple(T) -> expr(tuple_to_list(T), S); expr([E | Es], S) -> @@ -241,13 +249,13 @@ external_call(Mod, Fun, ArgsList, Line, X, S) -> _Else -> % apply2, 1 or 2 check_funarg(W, ArgsList, Line, S1) end. - + eval_args(Mod, Fun, ArgsTerm, Line, S, ArgsList, Extra) -> {IsSimpleCall, M, F} = mod_fun(Mod, Fun), case term2list(ArgsTerm, [], S) of undefined -> S1 = unresolved(M, F, -1, Line, S), - expr(ArgsList, S1); + expr(ArgsList, S1); ArgsList2 when not IsSimpleCall -> S1 = unresolved(M, F, length(ArgsList2), Line, S), expr(ArgsList, S1); @@ -288,14 +296,14 @@ fun_args(apply2, [FunArg, Args]) -> {FunArg, Args}; fun_args(1, [FunArg | Args]) -> {FunArg, Args}; fun_args(2, [_Node, FunArg | Args]) -> {FunArg, Args}. -list2term([A | As]) -> +list2term([A | As]) -> {cons, 0, A, list2term(As)}; -list2term([]) -> +list2term([]) -> {nil, 0}. term2list({cons, _Line, H, T}, L, S) -> term2list(T, [H | L], S); -term2list({nil, _Line}, L, _S) -> +term2list({nil, _Line}, L, _S) -> reverse(L); term2list({var, _, Var}, L, S) -> case keysearch(Var, 1, S#xrefr.matches) of @@ -332,11 +340,11 @@ handle_call(Locality, To0, Line, S, IsUnres) -> true -> S end, - case Locality of - local -> + case Locality of + local -> S1#xrefr{el = [Call | S1#xrefr.el], l_call_at = [CallAt | S1#xrefr.l_call_at]}; - external -> + external -> S1#xrefr{ex = [Call | S1#xrefr.ex], x_call_at = [CallAt | S1#xrefr.x_call_at]} end. diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl index a7855b0bb9..f9d062ef85 100644 --- a/lib/tools/test/xref_SUITE.erl +++ b/lib/tools/test/xref_SUITE.erl @@ -39,11 +39,11 @@ -export([all/1, init/1, fini/1]). -export([xref/1, - addrem/1, convert/1, intergraph/1, lines/1, loops/1, + addrem/1, convert/1, intergraph/1, lines/1, loops/1, no_data/1, modules/1]). -export([files/1, - add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1, + add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1, replace/1, update/1, deprecated/1, trycatch/1, abstract_modules/1, fun_mfa/1, qlc/1]). @@ -82,7 +82,7 @@ init(Conf) when is_list(Conf) -> ?line ok = erl_tar:extract(TarFile, [compressed]), ?line ok = file:delete(TarFile), [{copy_dir, CopyDir} | Conf]. - + fini(Conf) when is_list(Conf) -> %% Nothing. Conf. @@ -120,7 +120,7 @@ addrem(Conf) when is_list(Conf) -> LCallAt_m1 = [], XCallAt_m1 = [{E1,13}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, XC_m1, LC_m1), D2 = {F2,7}, @@ -132,7 +132,7 @@ addrem(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E2,96}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, XC_m2, LC_m2), ?line S5 = set_up(S2), @@ -142,7 +142,7 @@ addrem(Conf) when is_list(Conf) -> ?line {ok, XMod2, S6a} = remove_module(S6, m2), ?line [a2] = XMod2#xref_mod.app_name, ?line S7 = set_up(S6a), - + ?line AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, ?line S9 = add_application(S7, AppInfo1), ?line S10 = set_up(S9), @@ -186,7 +186,7 @@ convert(Conf) when is_list(Conf) -> LCallAt_m1 = [], XCallAt_m1 = [{E1,13},{E2,17},{E4,7}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, XC_m1, LC_m1), D2 = {F2,7}, @@ -200,7 +200,7 @@ convert(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E3,96},{E6,12},{UE1,77}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, XC_m2, LC_m2), D4 = {F4,6}, @@ -213,7 +213,7 @@ convert(Conf) when is_list(Conf) -> LCallAt_m3 = [{E5,19}], XCallAt_m3 = [{UE2,22}], Info3 = #xref_mod{name = m3, app_name = [a3]}, - ?line S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, + ?line S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, XC_m3, LC_m3), Info4 = #xref_mod{name = m4, app_name = [a2]}, @@ -303,7 +303,7 @@ convert(Conf) when is_list(Conf) -> ?line {ok, _} = eval("(XXL) (Lin) (Fun) E", AllCallAt, S), ?line {ok, _} = eval("(XXL) (XXL) (Lin) (Fun) E", AllCallAt, S), - ?line {ok, _} = eval(f("(XXL) (Lin) ~p", [[E1, E6]]), + ?line {ok, _} = eval(f("(XXL) (Lin) ~p", [[E1, E6]]), [{{D1,D3},[13]}, {{D7,D4},[12]}], S), ?line {ok, _} = eval(f("(Fun) ~p", [AllMs]), AllE, S), ?line {ok, _} = eval("(Fun) [m1->m2,m2->m3]", [E1,E2,E6], S), @@ -323,7 +323,7 @@ intergraph(Conf) when is_list(Conf) -> F3 = {m1,f3,3}, F4 = {m1,f4,4}, F5 = {m1,f5,5}, - + F6 = {m2,f1,6}, % X F7 = {m2,f1,7}, F8 = {m2,f1,8}, @@ -339,7 +339,7 @@ intergraph(Conf) when is_list(Conf) -> E5 = {F4,F2}, E6 = {F5,F4}, E7 = {F4,F5}, - + E8 = {F6,F7}, E9 = {F7,F8}, E10 = {F8,F1}, % X @@ -363,9 +363,9 @@ intergraph(Conf) when is_list(Conf) -> LCallAt_m1 = [{E1,1},{E2,2},{E3,3},{E5,5},{E6,6},{E7,7}], XCallAt_m1 = [{E1,4}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, XC_m1, LC_m1), - + D6 = {F6,6}, D7 = {F7,7}, D8 = {F8,8}, @@ -380,7 +380,7 @@ intergraph(Conf) when is_list(Conf) -> LCallAt_m2 = [{E8,8},{E9,9},{E11,11},{E12,12},{E13,13},{E14,14}], XCallAt_m2 = [{E10,10},{E15,15}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, XC_m2, LC_m2), AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, @@ -397,13 +397,13 @@ intergraph(Conf) when is_list(Conf) -> ?line {ok, _} = eval("EE | m2", [{F6,F1}], S), ?line {ok, _} = eval("EE | m2 + EE | m2", [{F6,F1}], S), - ?line {ok, _} = eval("(Fun)(Lin)(E | m1)", + ?line {ok, _} = eval("(Fun)(Lin)(E | m1)", to_external(union(set(XC_m1), set(LC_m1))), S), - ?line {ok, _} = eval("(XXL)(ELin) (EE | m1)", - [{{D2,D1},[1,2,4]},{{D4,D2},[5]},{{D5,D4},[6]},{{D4,D5},[7]}], + ?line {ok, _} = eval("(XXL)(ELin) (EE | m1)", + [{{D2,D1},[1,2,4]},{{D4,D2},[5]},{{D5,D4},[6]},{{D4,D5},[7]}], S), ?line {ok, _} = eval("(XXL)(ELin)(EE | m2)", [{{D6,D1},[8,11,12]}], S), - ?line {ok, _} = eval("(XXL)(ELin)(ELin)(EE | m2)", + ?line {ok, _} = eval("(XXL)(ELin)(ELin)(EE | m2)", [{{D6,D1},[8,11,12]}], S), %% Combining graphs (equal or different): @@ -420,15 +420,15 @@ intergraph(Conf) when is_list(Conf) -> ?line {ok, _} = eval("EE | m1 + E | m1", LC_m1, S), ?line {ok, _} = eval(f("EE | ~p + E | ~p", [F2, F2]), [E1,E2], S), %% [1,4] from 'calls' is a subset of [1,2,4] from Inter Call Graph: - ?line {ok, _} = eval(f("(XXL)(Lin) (E | ~p)", [F2]), + ?line {ok, _} = eval(f("(XXL)(Lin) (E | ~p)", [F2]), [{{D2,D1},[1,4]},{{D2,D3},[2]}], S), - ?line {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F2]), + ?line {ok, _} = eval(f("(XXL)(ELin) (EE | ~p)", [F2]), [{{D2,D1},[1,2,4]}], S), ?line {ok, _} = eval(f("(XXL)((ELin)(EE | ~p) + (Lin)(E | ~p))", [F2, F2]), [{{D2,D1},[1,2,4]},{{D2,D3},[2]}], S), - ?line {ok, _} = - eval(f("(XXL)((ELin) ~p + (Lin) ~p)", [{F2, F1}, {F2, F1}]), + ?line {ok, _} = + eval(f("(XXL)((ELin) ~p + (Lin) ~p)", [{F2, F1}, {F2, F1}]), [{{D2,D1},[1,2,4]}], S), ?line {ok, _} = eval(f("(Fun)(Lin) ~p", [{F2, F1}]), [E1], S), %% The external call E4 is included in the reply: @@ -438,7 +438,7 @@ intergraph(Conf) when is_list(Conf) -> %% The local call E1 is included in the reply: ?line {ok, _} = eval("(XXL)(Lin)(XC | m1)", [{{D2,D1},[1,4]}], S), - ?line {ok, _} = eval(f("(LLin) (E | ~p || ~p) + (XLin) (E | ~p || ~p)", + ?line {ok, _} = eval(f("(LLin) (E | ~p || ~p) + (XLin) (E | ~p || ~p)", [F2, F1, F2, F1]), [{E4,[1,4]}], S), ?line {ok, _} = eval("# (ELin) E", 6, S), @@ -449,7 +449,7 @@ lines(suite) -> []; lines(doc) -> ["More test of Inter Call Graph, and regular expressions"]; lines(Conf) when is_list(Conf) -> S0 = new(), - + F1 = {m1,f1,1}, % X F2 = {m1,f2,2}, F3 = {m1,f3,3}, @@ -464,14 +464,14 @@ lines(Conf) when is_list(Conf) -> E5 = {F2,F4}, % X E6 = {F5,F6}, E7 = {F6,F4}, % X - + D1 = {F1,1}, D2 = {F2,2}, D3 = {F3,3}, D4 = {F4,4}, D5 = {F5,5}, D6 = {F6,6}, - + DefAt_m1 = [D1,D2,D3,D5,D6], X_m1 = [F1,F5], % L_m1 = [F2,F3,F6], @@ -480,7 +480,7 @@ lines(Conf) when is_list(Conf) -> LCallAt_m1 = [{E1,1},{E3,3},{E6,6}], XCallAt_m1 = [{E2,2},{E4,4},{E5,5},{E7,7}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, XC_m1, LC_m1), DefAt_m2 = [D4], @@ -491,9 +491,9 @@ lines(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, XC_m2, LC_m2), - + AppInfo1 = #xref_app{name = a1, rel_name = [r1]}, ?line S5 = add_application(S2, AppInfo1), AppInfo2 = #xref_app{name = a2, rel_name = [r1]}, @@ -509,10 +509,10 @@ lines(Conf) when is_list(Conf) -> {{D5,D4},[6]}], S), ?line {ok, _} = eval("(XXL)(Lin) (E | m1)", [{{D1,D2},[1]},{{D1,D4},[4]},{{D2,D1},[2]}, - {{D2,D4},[5]},{{D3,D2},[3]},{{D5,D6},[6]},{{D6,D4},[7]}], + {{D2,D4},[5]},{{D3,D2},[3]},{{D5,D6},[6]},{{D6,D4},[7]}], S), ?line {ok, _} = eval("(E | m1) + (EE | m1)", - [E1,E2,E3,E4,E5,E6,E7,{F1,F1},{F3,F1},{F3,F4},{F5,F4}], + [E1,E2,E3,E4,E5,E6,E7,{F1,F1},{F3,F1},{F3,F4},{F5,F4}], S), ?line {ok, _} = eval("(Lin)(E | m1)", [{E4,[4]},{E1,[1]},{E2,[2]},{E5,[5]}, @@ -567,7 +567,7 @@ lines(Conf) when is_list(Conf) -> loops(suite) -> []; loops(doc) -> ["More Inter Call Graph, loops and \"unusual\" cases"]; loops(Conf) when is_list(Conf) -> - S0 = new(), + S0 = new(), F1 = {m1,f1,1}, % X F2 = {m1,f2,2}, @@ -582,7 +582,7 @@ loops(Conf) when is_list(Conf) -> E3 = {F3,F4}, E4 = {F4,F5}, E5 = {F5,F3}, % X - + D1 = {F1,1}, D2 = {F2,2}, D3 = {F3,3}, @@ -598,7 +598,7 @@ loops(Conf) when is_list(Conf) -> LCallAt_m1 = [{E2,2},{E3,3},{E4,4}], XCallAt_m1 = [{E1,1},{E5,5}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, XC_m1, LC_m1), ?line S = set_up(S1), @@ -659,16 +659,16 @@ modules(Conf) when is_list(Conf) -> ?line {ok, y} = compile:file(Y, [debug_info, {outdir,EB1_1}]), ?line {ok, S0} = xref_base:new([{xref_mode, modules}]), - ?line {ok, release2, S1} = + ?line {ok, release2, S1} = xref_base:add_release(S0, Dir, [{name,release2}]), ?line S = set_up(S1), ?line {{error, _, {unavailable_analysis, undefined_function_calls}}, _} = xref_base:analyze(S, undefined_function_calls), - ?line {{error, _, {unavailable_analysis, locals_not_used}}, _} = + ?line {{error, _, {unavailable_analysis, locals_not_used}}, _} = xref_base:analyze(S, locals_not_used), - ?line {{error, _, {unavailable_analysis, {call, foo}}}, _} = + ?line {{error, _, {unavailable_analysis, {call, foo}}}, _} = xref_base:analyze(S, {call, foo}), - ?line {{error, _, {unavailable_analysis, {use, foo}}}, _} = + ?line {{error, _, {unavailable_analysis, {use, foo}}}, _} = xref_base:analyze(S, {use, foo}), ?line analyze(undefined_functions, [{x,undef,0}], S), ?line 5 = length(xref_base:info(S)), @@ -681,7 +681,7 @@ modules(Conf) when is_list(Conf) -> ok. files(suite) -> - [add, default, info, lib, read, read2, remove, replace, update, + [add, default, info, lib, read, read2, remove, replace, update, deprecated, trycatch, abstract_modules, fun_mfa, qlc]. add(suite) -> []; @@ -708,7 +708,7 @@ add(Conf) when is_list(Conf) -> {unix, _} -> ?line make_udir(UDir), ?line make_ufile(UFile); - _ -> + _ -> true end, @@ -743,20 +743,20 @@ add(Conf) when is_list(Conf) -> xref_base:add_release(S, foo, [{builtins,not_a_value}]), ?line {error, _, {invalid_filename,{foo,bar}}} = xref_base:add_release(S, {foo,bar}, []), - ?line {ok, S1} = + ?line {ok, S1} = xref_base:set_default(S, [{verbose,false}, {warnings, false}]), ?line case os:type() of {unix, _} -> - ?line {error, _, {file_error, _, _}} = + ?line {error, _, {file_error, _, _}} = xref_base:add_release(S, UDir); _ -> true end, - ?line {error, _, {file_error, _, _}} = + ?line {error, _, {file_error, _, _}} = xref_base:add_release(S, fname(["/a/b/c/d/e/f","__foo"])), - ?line {ok, release2, S2} = + ?line {ok, release2, S2} = xref_base:add_release(S1, Dir, [{name,release2}]), - ?line {error, _, {module_clash, {x, _, _}}} = + ?line {error, _, {module_clash, {x, _, _}}} = xref_base:add_module(S2, Xbeam), ?line {ok, S3} = xref_base:remove_release(S2, release2), ?line {ok, rel2, S4} = xref_base:add_release(S3, Dir), @@ -764,11 +764,11 @@ add(Conf) when is_list(Conf) -> xref_base:add_release(S4, Dir), ?line {ok, S5} = xref_base:remove_release(S4, rel2), %% One unreadable file and one JAM file found (no verification here): - ?line {ok, [], S6} = xref_base:add_directory(S5, fname(CopyDir,"dir"), + ?line {ok, [], S6} = xref_base:add_directory(S5, fname(CopyDir,"dir"), [{recurse,true}, {warnings,true}]), ?line case os:type() of {unix, _} -> - ?line {error, _, {file_error, _, _}} = + ?line {error, _, {file_error, _, _}} = xref_base:add_directory(S6, UDir); _ -> true @@ -803,7 +803,7 @@ default(Conf) when is_list(Conf) -> xref_base:set_default(S, [not_an_option]), ?line D = xref_base:get_default(S), - ?line [{builtins,false},{recurse,false},{verbose,false},{warnings,true}] = + ?line [{builtins,false},{recurse,false},{verbose,false},{warnings,true}] = D, ?line ok = xref_base:delete(S), @@ -831,7 +831,7 @@ info(Conf) when is_list(Conf) -> ?line {error, _, {no_such_info, release}} = xref:info(s, release), ?line {error, _, {no_such_info, release}} = xref:info(s, release, rel), ?line {error, _, {no_such_module, mod}} = xref:info(s, modules, mod), - ?line {error, _, {no_such_application, app}} = + ?line {error, _, {no_such_application, app}} = xref:info(s, applications, app), ?line {error, _, {no_such_release, rel}} = xref:info(s, releases, rel), ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), @@ -845,9 +845,9 @@ info(Conf) when is_list(Conf) -> ?line [{rel2,_}] = xref:info(s, releases, rel2), ?line {error, _, {no_such_library, foo}} = xref:info(s, libraries, [foo]), - ?line {ok, lib1} = + ?line {ok, lib1} = compile:file(fname(LDir,lib1),[debug_info,{outdir,LDir}]), - ?line {ok, lib2} = + ?line {ok, lib2} = compile:file(fname(LDir,lib2),[debug_info,{outdir,LDir}]), ?line ok = xref:set_library_path(s, [LDir], [{verbose,false}]), ?line [{lib1,_}, {lib2, _}] = xref:info(s, libraries), @@ -883,13 +883,13 @@ lib(Conf) when is_list(Conf) -> xref:set_library_path(s, ["foo"], [not_an_option]), ?line {error, _, {invalid_path,otp}} = xref:set_library_path(s,otp), ?line {error, _, {invalid_path,[""]}} = xref:set_library_path(s,[""]), - ?line {error, _, {invalid_path,[[$a | $b]]}} = + ?line {error, _, {invalid_path,[[$a | $b]]}} = xref:set_library_path(s,[[$a | $b]]), ?line {error, _, {invalid_path,[otp]}} = xref:set_library_path(s,[otp]), ?line {ok, []} = xref:get_library_path(s), ?line ok = xref:set_library_path(s, [Dir], [{verbose,false}]), ?line {ok, UnknownFunctions} = xref:q(s, "U"), - ?line [{lib1,unknown,0}, {lib2,local,0}, + ?line [{lib1,unknown,0}, {lib2,local,0}, {lib2,unknown,0}, {unknown,unknown,0}] = UnknownFunctions, ?line {ok, [{lib2,f,0},{lib3,f,0}]} = xref:q(s, "DF"), @@ -934,7 +934,7 @@ lib(Conf) when is_list(Conf) -> ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), ?line {ok, cp} = xref:add_module(s, fname(Dir,"cp.beam")), ?line {ok, [{lists, sort, 1}]} = xref:q(s, "U"), - ?line ok = xref:set_library_path(s, code_path), + ?line ok = xref:set_library_path(s, code_path), ?line {ok, []} = xref:q(s, "U"), ?line check_state(s), ?line xref:stop(s), @@ -1010,18 +1010,18 @@ do_read(File, Version) -> ?line {ok, CallsB} = xref:q(s, "(Lin) (E - UC) "), ?line ok = check_state(s), ?line {ok, XU} = xref:q(s, "XU"), - ?line Erl = set([{erlang,length,1},{erlang,integer,1}, + ?line Erl = set([{erlang,length,1},{erlang,integer,1}, {erlang,binary_to_term,1}]), - ?line [{erlang,binary_to_term,1},{erlang,length,1}] = + ?line [{erlang,binary_to_term,1},{erlang,length,1}] = to_external(intersection(set(XU), Erl)), - ?line xref:stop(s). + ?line xref:stop(s). %% What is expected when xref_SUITE_data/read/read.erl is added: read_expected(Version) -> %% Line positions in xref_SUITE_data/read/read.erl: - POS1 = 28, POS2 = POS1+10, POS3 = POS2+6, POS4 = POS3+6, POS5 = POS4+10, - POS6 = POS5+5, POS7 = POS6+6, POS8 = POS7+6, POS9 = POS8+8, - POS10 = POS9+10, POS11 = POS10+7, POS12 = POS11+8, POS13 = POS12+10, + POS1 = 28, POS2 = POS1+10, POS3 = POS2+6, POS4 = POS3+6, POS5 = POS4+10, + POS6 = POS5+5, POS7 = POS6+6, POS8 = POS7+6, POS9 = POS8+8, + POS10 = POS9+10, POS11 = POS10+7, POS12 = POS11+8, POS13 = POS12+10, POS14 = POS13+18, % POS15 = POS14+23, FF = {read,funfuns,0}, @@ -1162,7 +1162,7 @@ read_expected(Version) -> {POS14+17,{{read,bi,0},{read,bi,0}}}], OK = case Version of - abstract_v1 -> + abstract_v1 -> [{POS8+3, {FF,{erlang,apply,3}}}, {POS10+1, {FF,{erlang,apply,3}}}, {POS10+6, {FF,{erlang,apply,3}}}] @@ -1170,7 +1170,7 @@ read_expected(Version) -> [{0,{FF,{read,'$F_EXPR',178}}}, {0,{FF,{modul,'$F_EXPR',179}}}] ++ O1; - _ -> + _ -> % [{POS15+2,{{read,bi,0},{foo,t,0}}}, % {POS15+3,{{read,bi,0},{bar,t,0}}}, % {POS15+6,{{read,bi,0},{read,local,0}}}, @@ -1183,18 +1183,34 @@ read_expected(Version) -> end, %% When builtins =:= true: - OKB = [{POS13+1,{FF,{erts_debug,apply,4}}}, - {POS13+2,{FF,{erts_debug,apply,4}}}, - {POS13+3,{FF,{erts_debug,apply,4}}}, - {POS1+3, {FF,{erlang,binary_to_term,1}}}, - {POS3+1, {FF,{erlang,spawn,3}}}, - {POS3+2, {FF,{erlang,spawn,3}}}, - {POS3+3, {FF,{erlang,spawn_link,3}}}, - {POS3+4, {FF,{erlang,spawn_link,3}}}, - {POS6+4, {FF,{erlang,spawn,3}}}, - {POS13+5, {{read,bi,0},{erlang,length,1}}}, - {POS14+3, {{read,bi,0},{erlang,length,1}}}] - ++ OK, + OKB1 = [{POS13+1,{FF,{erts_debug,apply,4}}}, + {POS13+2,{FF,{erts_debug,apply,4}}}, + {POS13+3,{FF,{erts_debug,apply,4}}}, + {POS1+3, {FF,{erlang,binary_to_term,1}}}, + {POS3+1, {FF,{erlang,spawn,3}}}, + {POS3+2, {FF,{erlang,spawn,3}}}, + {POS3+3, {FF,{erlang,spawn_link,3}}}, + {POS3+4, {FF,{erlang,spawn_link,3}}}, + {POS6+4, {FF,{erlang,spawn,3}}}, + {POS13+5, {{read,bi,0},{erlang,length,1}}}, + {POS14+3, {{read,bi,0},{erlang,length,1}}}], + + %% Operators (OTP-8647): + OKB = case Version of + abstract_v1 -> + []; + _ -> + [{POS13+16, {{read,bi,0},{erlang,'!',2}}}, + {POS13+16, {{read,bi,0},{erlang,'-',1}}}, + {POS13+16, {{read,bi,0},{erlang,self,0}}}] + end + ++ [{POS14+19, {{read,bi,0},{erlang,'+',2}}}, + {POS14+21, {{read,bi,0},{erlang,'+',2}}}, + {POS13+16, {{read,bi,0},{erlang,'==',2}}}, + {POS14+15, {{read,bi,0},{erlang,'==',2}}}, + {POS13+5, {{read,bi,0},{erlang,'>',2}}}, + {POS14+3, {{read,bi,0},{erlang,'>',2}}}] + ++ OKB1 ++ OK, {U, OK, OKB}. @@ -1217,9 +1233,9 @@ read2(Conf) when is_list(Conf) -> spawn_opt(fun() -> foo end, [link]), spawn_opt(f(), {read2,f}, [{min_heap_size,1000}]), - spawn_opt(f(), + spawn_opt(f(), fun() -> f() end, [flopp]), - spawn_opt(f(), + spawn_opt(f(), read2, f, [], []); f() -> %% Duplicated unresolved calls are ignored: @@ -1237,7 +1253,7 @@ read2(Conf) when is_list(Conf) -> ?line {ok, U2} = xref:q(s, "(Lin) UC"), ?line {ok, OK2} = xref:q(s, "(Lin) (E - UC)"), ?line true = U =:= U2, - ?line true = OK =:= OK2, + ?line true = OK =:= OK2, ?line ok = check_state(s), ?line xref:stop(s), @@ -1304,7 +1320,7 @@ replace(Conf) when is_list(Conf) -> ?line {ok, true} = xref:set_default(s, warnings, false), ?line {ok, rel2} = xref:add_release(s, Dir, []), ?line {error, _, _} = xref:replace_application(s, app1, "no_data"), - ?line {error, _, {no_such_application, app12}} = + ?line {error, _, {no_such_application, app12}} = xref:replace_application(s, app12, A1_0, []), ?line {error, _, {invalid_filename,{foo,bar}}} = xref:replace_application(s, app1, {foo,bar}, []), @@ -1312,7 +1328,7 @@ replace(Conf) when is_list(Conf) -> xref:replace_application(s, foo, bar, [not_an_option]), ?line {error, _, {invalid_options,[{builtins,not_a_value}]}} = xref:replace_application(s, foo, bar, [{builtins,not_a_value}]), - ?line {ok, app1} = + ?line {ok, app1} = xref:replace_application(s, app1, A1_0), ?line [{_, AppInfo}] = xref:info(s, applications, app1), ?line {value, {release, [rel2]}} = keysearch(release, 1, AppInfo), @@ -1332,14 +1348,14 @@ replace(Conf) when is_list(Conf) -> ?line {ok, x} = compile:file(X, [no_debug_info, {outdir,EB1_1}]), ?line {error, _, {no_debug_info, _}} = xref:replace_module(s, x, Xbeam), - ?line {error, _, {module_mismatch, x,y}} = + ?line {error, _, {module_mismatch, x,y}} = xref:replace_module(s, x, Ybeam), ?line case os:type() of {unix, _} -> ?line hide_file(Ybeam), - ?line {error, _, {file_error, _, _}} = + ?line {error, _, {file_error, _, _}} = xref:replace_module(s, x, Ybeam); - _ -> + _ -> true end, ?line ok = xref:remove_module(s, x), @@ -1362,16 +1378,16 @@ update(Conf) when is_list(Conf) -> Source = fname(Dir, "x.erl"), Beam = fname(Dir, "x.beam"), ?line copy_file(fname(Dir, "x.erl.1"), Source), - ?line {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), - + ?line {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), + ?line {ok, _} = start(s), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), ?line {ok, [x]} = xref:add_directory(s, Dir, [{builtins,true}]), ?line {error, _, {invalid_options,[not_an_option]}} = xref:update(s, [not_an_option]), ?line {ok, []} = xref:update(s), ?line {ok, [{erlang,atom_to_list,1}]} = xref:q(s, "XU"), - + ?line [{x, ModInfo}] = xref:info(s, modules, x), ?line case keysearch(directory, 1, ModInfo) of {value, {directory, Dir}} -> ok @@ -1379,7 +1395,7 @@ update(Conf) when is_list(Conf) -> timer:sleep(2000), % make sure modification time has changed ?line copy_file(fname(Dir, "x.erl.2"), Source), - ?line {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), + ?line {ok, x} = compile:file(Source, [debug_info, {outdir,Dir}]), ?line {ok, [x]} = xref:update(s, []), ?line {ok, [{erlang,list_to_atom,1}]} = xref:q(s, "XU"), @@ -1454,11 +1470,11 @@ deprecated(Conf) when is_list(Conf) -> DF = usort(DF_3++[{{M9,t,0},{M9,f,1}}]), ?line {ok,DF} = xref:analyze(s, deprecated_function_calls), - ?line {ok,DF_1} = + ?line {ok,DF_1} = xref:analyze(s, {deprecated_function_calls,next_version}), - ?line {ok,DF_2} = + ?line {ok,DF_2} = xref:analyze(s, {deprecated_function_calls,next_major_release}), - ?line {ok,DF_3} = + ?line {ok,DF_3} = xref:analyze(s, {deprecated_function_calls,eventually}), D = to_external(range(from_term(DF))), @@ -1467,11 +1483,11 @@ deprecated(Conf) when is_list(Conf) -> D_3 = to_external(range(from_term(DF_3))), ?line {ok,D} = xref:analyze(s, deprecated_functions), - ?line {ok,D_1} = + ?line {ok,D_1} = xref:analyze(s, {deprecated_functions,next_version}), - ?line {ok,D_2} = + ?line {ok,D_2} = xref:analyze(s, {deprecated_functions,next_major_release}), - ?line {ok,D_3} = + ?line {ok,D_3} = xref:analyze(s, {deprecated_functions,eventually}), ?line ok = check_state(s), @@ -1516,11 +1532,11 @@ deprecated(Conf) when is_list(Conf) -> DFa = DFa_3, ?line {ok,DFa} = xref:analyze(s, deprecated_function_calls), - ?line {ok,DFa_1} = + ?line {ok,DFa_1} = xref:analyze(s, {deprecated_function_calls,next_version}), - ?line {ok,DFa_2} = + ?line {ok,DFa_2} = xref:analyze(s, {deprecated_function_calls,next_major_release}), - ?line {ok,DFa_3} = + ?line {ok,DFa_3} = xref:analyze(s, {deprecated_function_calls,eventually}), ?line ok = check_state(s), @@ -1564,11 +1580,11 @@ deprecated(Conf) when is_list(Conf) -> DFb = usort(DFb_2++[{{M,bar,2},{M,t,0}},{{M,g,3},{M,bar,2}}]), ?line {ok,DFb} = xref:analyze(s, deprecated_function_calls), - ?line {ok,DFb_1} = + ?line {ok,DFb_1} = xref:analyze(s, {deprecated_function_calls,next_version}), - ?line {ok,DFb_2} = + ?line {ok,DFb_2} = xref:analyze(s, {deprecated_function_calls,next_major_release}), - ?line {ok,DFb_3} = + ?line {ok,DFb_3} = xref:analyze(s, {deprecated_function_calls,eventually}), ?line ok = check_state(s), @@ -1599,7 +1615,7 @@ trycatch(Conf) when is_list(Conf) -> catch error:a -> err:e1(); error:b -> err:e2() - after + after fini:shed() end. ">>, @@ -1616,7 +1632,7 @@ trycatch(Conf) when is_list(Conf) -> {{{A,A,0},{err,e2,0}},[13]}, {{{A,A,0},{fini,shed,0}},[15]}, {{{A,A,0},{foo,bar,0}},[7]}, - {{{A,A,0},{foo,foo,0}},[9]}]} = + {{{A,A,0},{foo,foo,0}},[9]}]} = xref:q(s, "(Lin) (E | trycatch:trycatch/0)"), ?line ok = check_state(s), @@ -1662,7 +1678,7 @@ abstract_modules(Conf) when is_list(Conf) -> {{{A,args,1},{A,local,1}},[6]}, {{{A,args,1},{A,new,2}},[8]}, {{{A,local,1},{A,module_info,1}},[12]}, - {{{param,new,2},{param,instance,2}},[0]}]} = + {{{param,new,2},{param,instance,2}},[0]}]} = xref:q(s, "(Lin) E"), ?line {ok,[{param,args,1}, {param,instance,2}, @@ -1747,10 +1763,10 @@ qlc(Conf) when is_list(Conf) -> t() -> dets:open_file(t, []), dets:insert(t, [{1,a},{2,b},{3,c},{4,d}]), - MS = ets:fun2ms(fun({X,Y}) when (X > 1) or (X < 5) -> {Y} + MS = ets:fun2ms(fun({X,Y}) when (X > 1) or (X < 5) -> {Y} end), QH1 = dets:table(t, [{traverse, {select, MS}}]), - QH2 = qlc:q([{Y} || {X,Y} <- dets:table(t), + QH2 = qlc:q([{Y} || {X,Y} <- dets:table(t), (X > 1) or (X < 5)]), true = qlc:info(QH1) =:= qlc:info(QH2), dets:close(t), @@ -1783,7 +1799,7 @@ analyze(Conf) when is_list(Conf) -> xref_base:analyze(S0, undefined_function_calls, [not_an_option]), ?line {{error, _, {invalid_query,{q}}}, _} = xref_base:q(S0,{q}), ?line {{error, _, {unknown_analysis,foo}}, _} = xref_base:analyze(S0, foo), - ?line {{error, _, {unknown_constant,"foo:bar/-1"}}, _} = + ?line {{error, _, {unknown_constant,"foo:bar/-1"}}, _} = xref_base:analyze(S0, {use,{foo,bar,-1}}), CopyDir = ?copydir, @@ -1803,30 +1819,30 @@ analyze(Conf) when is_list(Conf) -> ?line {ok, rel2, S1} = xref_base:add_release(S0, Dir, [{verbose,false}]), ?line S = set_up(S1), - ?line {ok, _} = + ?line {ok, _} = analyze(undefined_function_calls, [{{x,xx,0},{x,undef,0}}], S), ?line {ok, _} = analyze(undefined_functions, [{x,undef,0}], S), ?line {ok, _} = analyze(locals_not_used, [{x,l,0},{x,l1,0}], S), ?line {ok, _} = analyze(exports_not_used, [{x,xx,0},{y,t,0}], S), - ?line {ok, _} = + ?line {ok, _} = analyze(deprecated_function_calls, [{{y,t,0},{x,t,0}}], S), ?line {ok, _} = analyze({deprecated_function_calls,next_version}, [], S), - ?line {ok, _} = + ?line {ok, _} = analyze({deprecated_function_calls,next_major_release}, [], S), - ?line {ok, _} = analyze({deprecated_function_calls,eventually}, + ?line {ok, _} = analyze({deprecated_function_calls,eventually}, [{{y,t,0},{x,t,0}}], S), ?line {ok, _} = analyze(deprecated_functions, [{x,t,0}], S), ?line {ok, _} = analyze({deprecated_functions,next_version}, [], S), - ?line {ok, _} = + ?line {ok, _} = analyze({deprecated_functions,next_major_release}, [], S), ?line {ok, _} = analyze({deprecated_functions,eventually}, [{x,t,0}], S), ?line {ok, _} = analyze({call, {x,xx,0}}, [{x,undef,0}], S), - ?line {ok, _} = + ?line {ok, _} = analyze({call, [{x,xx,0},{x,l,0}]}, [{x,l1,0},{x,undef,0}], S), ?line {ok, _} = analyze({use, {x,l,0}}, [{x,l1,0}], S), - ?line {ok, _} = + ?line {ok, _} = analyze({use, [{x,l,0},{x,l1,0}]}, [{x,l,0},{x,l1,0}], S), ?line {ok, _} = analyze({module_call, x}, [x], S), @@ -1881,7 +1897,7 @@ basic(Conf) when is_list(Conf) -> LCallAt_m1 = [{E7,12}], XCallAt_m1 = [{E1,13},{E2,17},{E4,7}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, XC_m1, LC_m1), D2 = {F2,7}, @@ -1895,7 +1911,7 @@ basic(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E3,96},{E6,12},{UE1,77}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, XC_m2, LC_m2), D4 = {F4,6}, @@ -1908,7 +1924,7 @@ basic(Conf) when is_list(Conf) -> LCallAt_m3 = [{E5,19}], XCallAt_m3 = [{UE2,22}], Info3 = #xref_mod{name = m3, app_name = [a3]}, - ?line S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, + ?line S3 = add_module(S2, Info3, DefAt_m3, X_m3, LCallAt_m3, XCallAt_m3, XC_m3, LC_m3), Info4 = #xref_mod{name = m4, app_name = [a2]}, @@ -1955,7 +1971,7 @@ basic(Conf) when is_list(Conf) -> ?line {ok, _} = eval(f("(Mod) ~p", [[F1,F6,F5]]), [m1,m3], S), ?line {ok, _} = eval("(Lin) M - (Lin) m1", [{F2,7},{F3,9},{F7,19},{F4,6},{F5,97},{UF2,0}], S), - ?line {ok, _} = eval(f("(Lin) M * (Lin) ~p", [[F1,F6]]), + ?line {ok, _} = eval(f("(Lin) M * (Lin) ~p", [[F1,F6]]), [{F1,12},{F6,3}], S), ?line {ok, _} = eval(f("X * ~p", [[F1, F2, F3, F4, F5]]), [F3, F4], S), @@ -1976,7 +1992,7 @@ basic(Conf) when is_list(Conf) -> ?line {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), [{{D1,D3},[13]},{{D1,D4},[7]}],S), ?line {ok, _} = eval(f("XC | (~p + ~p)", [F1, F2]), [E1,E4,E3,UE1], S), - ?line {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), + ?line {ok, _} = eval(f("(XXL) (Lin) (XC | ~p)", [F1]), [{{D1,D3},[13]},{{D1,D4},[7]}], S), ?line {ok, _} = eval("LC | m3", [E5], S), ?line {ok, _} = eval(f("LC | ~p", [F1]), [E7], S), @@ -1984,7 +2000,7 @@ basic(Conf) when is_list(Conf) -> ?line {ok, _} = eval("E | m1", [E1,E2,E4,E7], S), ?line {ok, _} = eval(f("E | ~p", [F1]), [E1,E7,E4], S), ?line {ok, _} = eval(f("E | (~p + ~p)", [F1, F2]), [E1,E7,E4,E3,UE1], S), - + ?line {ok, _} = eval("XC || m1", [E3,UE2], S), ?line {ok, _} = eval(f("XC || ~p", [F6]), [E3], S), ?line {ok, _} = eval(f("XC || (~p + ~p)", [F4, UF2]), [UE1,E4,E6], S), @@ -2012,18 +2028,18 @@ basic(Conf) when is_list(Conf) -> ?line {ok, _} = eval("components V", type_error, S), ?line {ok, _} = eval("components E + components E", type_error, S), - ?line {ok, _} = eval(f("range (closure E | ~p)", [[F1,F2]]), + ?line {ok, _} = eval(f("range (closure E | ~p)", [[F1,F2]]), [F6,F3,F7,F4,F5,UF1,UF2], S), - ?line {ok, _} = + ?line {ok, _} = eval(f("domain (closure E || ~p)", [[UF2,F7]]), [F1,F2,F6], S), ?line {ok, _} = eval("components E", [], S), ?line {ok, _} = eval("components (Mod) E", [[m1,m2,m3]], S), ?line {ok, _} = eval("components closure (Mod) E", [[m1,m2,m3]], S), - ?line {ok, _} = eval("condensation (Mod) E", + ?line {ok, _} = eval("condensation (Mod) E", [{[m1,m2,m3],[m1,m2,m3]},{[m1,m2,m3],[m17]}], S), - ?line {ok, _} = eval("condensation closure (Mod) E", + ?line {ok, _} = eval("condensation closure (Mod) E", [{[m1,m2,m3],[m1,m2,m3]},{[m1,m2,m3],[m17]}], S), - ?line {ok, _} = eval("condensation closure closure closure (Mod) E", + ?line {ok, _} = eval("condensation closure closure closure (Mod) E", [{[m1,m2,m3],[m1,m2,m3]},{[m1,m2,m3],[m17]}], S), ?line {ok, _} = eval("weak condensation (Mod) E", [{[m1,m2,m3],[m1,m2,m3]},{[m1,m2,m3],[m17]},{[m17],[m17]}], S), @@ -2035,11 +2051,11 @@ basic(Conf) when is_list(Conf) -> [[m1,m2,m3]], S), %% |, ||, ||| - ?line {ok, _} = eval("(Lin) E || V", type_error, S), - ?line {ok, _} = eval("E ||| (Lin) V", type_error, S), + ?line {ok, _} = eval("(Lin) E || V", type_error, S), + ?line {ok, _} = eval("E ||| (Lin) V", type_error, S), ?line {ok, _} = eval("E ||| m1", [E7], S), ?line {ok, _} = eval("closure E ||| m1", [E7,{F1,UF1},{F6,UF1}], S), - ?line {ok, _} = eval("closure E ||| [m1,m2]", + ?line {ok, _} = eval("closure E ||| [m1,m2]", [{F1,UF1},{F2,F7},{F1,F7},{F6,UF1},{F2,UF1},{F7,UF1},E7,E1,E2,E3], S), ?line {ok, _} = eval("AE | a1", [{a1,a1},{a1,a2},{a1,a3}], S), @@ -2095,7 +2111,7 @@ md(Conf) when is_list(Conf) -> Y = fname(Dir, "y__y.erl"), Xbeam = fname(Dir, "x__x.beam"), Ybeam = fname(Dir, "y__y.beam"), - + ?line {error, _, {invalid_filename,{foo,bar}}} = xref:m({foo,bar}), ?line {error, _, {invalid_filename,{foo,bar}}} = xref:d({foo,bar}), @@ -2171,7 +2187,7 @@ variables(Conf) when is_list(Conf) -> LCallAt_m1 = [], XCallAt_m1 = [{E1,13},{E3,17}], Info1 = #xref_mod{name = m1, app_name = [a1]}, - ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, + ?line S1 = add_module(S0, Info1, DefAt_m1, X_m1, LCallAt_m1, XCallAt_m1, XC_m1, LC_m1), D2 = {F2,7}, @@ -2183,11 +2199,11 @@ variables(Conf) when is_list(Conf) -> LCallAt_m2 = [], XCallAt_m2 = [{E2,96}], Info2 = #xref_mod{name = m2, app_name = [a2]}, - ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, + ?line S2 = add_module(S1, Info2, DefAt_m2, X_m2, LCallAt_m2, XCallAt_m2, XC_m2, LC_m2), ?line S = set_up(S2), - + ?line eval("T1=E, T2=E*T1, T3 = T2*T2, T4=range T3, T5=T3|T4, T5", [E1,E2,E3], S), ?line eval("((E*E)*(E*E)) | (range ((E*E)*(E*E)))", @@ -2202,16 +2218,16 @@ variables(Conf) when is_list(Conf) -> ?line {ok, S102} = eval("T2 := E | m2", [E2], S101), ?line {{ok, [{user, ['T0', 'T1', 'T2']}]}, _} = xref_base:variables(S102), ?line {ok, S103} = xref_base:forget(S102, 'T0'), - ?line {{ok, [{user, ['T1', 'T2']}]}, S104} = + ?line {{ok, [{user, ['T1', 'T2']}]}, S104} = xref_base:variables(S103, [user]), ?line {ok, S105} = xref_base:forget(S104), ?line {{ok, [{user, []}]}, S106} = xref_base:variables(S105), - ?line {{ok, [{predefined,_}]}, S107_0} = + ?line {{ok, [{predefined,_}]}, S107_0} = xref_base:variables(S106, [predefined]), - ?line {ok, S107_1} = + ?line {ok, S107_1} = eval("TT := E, TT2 := V, TT1 := TT * TT", [E1,E2,E3], S107_0), - ?line {{ok, [{user, ['TT', 'TT1', 'TT2']}]}, _} = + ?line {{ok, [{user, ['TT', 'TT1', 'TT2']}]}, _} = xref_base:variables(S107_1), ?line {ok, S107} = xref_base:forget(S107_1), @@ -2220,14 +2236,14 @@ variables(Conf) when is_list(Conf) -> Beam = fname(Dir, "lib1.beam"), ?line copy_file(fname(Dir, "lib1.erl"), Beam), - ?line {ok, S108} = + ?line {ok, S108} = xref_base:set_library_path(S107, [Dir], [{verbose,false}]), ?line {{error, _, _}, _} = xref_base:variables(S108, [{verbose,false}]), ?line {ok, S109} = xref_base:set_library_path(S108, [], [{verbose,false}]), ?line Tabs = length(ets:all()), - ?line {ok, S110} = eval("Eplus := closure E, TT := Eplus", + ?line {ok, S110} = eval("Eplus := closure E, TT := Eplus", 'closure()', S109), ?line {{ok, [{user, ['Eplus','TT']}]}, S111} = xref_base:variables(S110), ?line {ok, S112} = xref_base:forget(S111, ['TT','Eplus']), @@ -2289,7 +2305,7 @@ unused_locals(Conf) when is_list(Conf) -> ?line {ok, []} = xref:analyse(s, locals_not_used), ?line ok = check_state(s), ?line xref:stop(s), - + ?line ok = file:delete(File1), ?line ok = file:delete(Beam1), ?line ok = file:delete(File2), @@ -2303,7 +2319,7 @@ format_error(suite) -> []; format_error(doc) -> ["Format error messages"]; format_error(Conf) when is_list(Conf) -> ?line {ok, _Pid} = start(s), - ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), + ?line ok = xref:set_default(s, [{verbose,false}, {warnings, false}]), %% Parse error messages. ?line "Invalid regular expression \"add(\"" ++ _ = @@ -2332,7 +2348,7 @@ format_error(Conf) when is_list(Conf) -> %% Other messages ?line 'Variable \'QQ\' used before set\n' = fatom(xref:q(s,"QQ")), - ?line 'Unknown constant a\n' = + ?line 'Unknown constant a\n' = fatom(xref:q(s,"{a} of E")), %% Testing xref_parser:t2s/1. @@ -2341,12 +2357,12 @@ format_error(Conf) when is_list(Conf) -> ?line 'Variable assigned more than once: E = E + E\n' = fatom(xref:q(s,"E=E + E")), ?line "Operator applied to argument(s) of different or invalid type(s): " - "E + V * V\n" = + "E + V * V\n" = flatten(xref:format_error(xref:q(s,"E + (V * V)"))), ?line {error,xref_compiler,{type_error,"(V + V) * E"}} = xref:q(s,"(V + V) * E"), ?line "Type does not match structure of constant: [m:f/3 -> g:h/17] : " - "App\n" = + "App\n" = flatten(xref:format_error(xref:q(s,"[{{m,f,3},{g,h,17}}] : App"))), ?line 'Type does not match structure of constant: [m -> f, g -> h] : Fun\n' = fatom(xref:q(s,"[{m,f},g->h] : Fun")), @@ -2360,11 +2376,11 @@ format_error(Conf) when is_list(Conf) -> xref:q(s,"condensation (# E + # V)"), ?line {error,xref_compiler,{type_error,"range (# E + # E)"}} = xref:q(s,"range (#E + #E)"), - ?line {error,xref_compiler,{type_error,"range (# E)"}} = + ?line {error,xref_compiler,{type_error,"range (# E)"}} = xref:q(s,"range #E"), % Hm... ?line {error,xref_compiler,{type_error,"E + # E"}} = xref:q(s,"E + #E + #E"), % Hm... - ?line {error,xref_compiler,{type_error,"V * E || V | V"}} = + ?line {error,xref_compiler,{type_error,"V * E || V | V"}} = xref:q(s,"V * (E || V) | V"), ?line {error,xref_compiler,{type_error,"E || (E | V)"}} = xref:q(s,"V * E || (E | V)"), @@ -2421,7 +2437,7 @@ eval(Query, E, S) -> ?format("------------------------------~n", []), ?format("Evaluating ~p~n", [Query]), ?line {Answer, NewState} = xref_base:q(S, Query, [{verbose, false}]), - {Reply, Expected} = + {Reply, Expected} = case Answer of {ok, R} when is_list(E) -> {unsetify(R), sort(E)}; @@ -2430,7 +2446,7 @@ eval(Query, E, S) -> {error, _Module, Reason} -> {element(1, Reason), E} end, - if + if Reply =:= Expected -> ?format("As expected, got ~n~p~n", [Expected]), {ok, NewState}; @@ -2442,7 +2458,7 @@ eval(Query, E, S) -> analyze(Query, E, S) -> ?format("------------------------------~n", []), ?format("Evaluating ~p~n", [Query]), - ?line {{ok, L}, NewState} = + ?line {{ok, L}, NewState} = xref_base:analyze(S, Query, [{verbose, false}]), case {unsetify(L), sort(E)} of {X,X} -> @@ -2461,7 +2477,7 @@ unsetify(S) -> %% Note: assumes S has been set up; the new state is not returned eval(Query, S) -> - ?line {{ok, Answer}, _NewState} = + ?line {{ok, Answer}, _NewState} = xref_base:q(S, Query, [{verbose, false}]), unsetify(Answer). @@ -2514,7 +2530,7 @@ check_state(S) -> functions_mode_check(S, Info) end. -%% The manual mentions some facts that should always hold. +%% The manual mentions some facts that should always hold. %% Here they are again. functions_mode_check(S, Info) -> %% F = L + X, @@ -2526,7 +2542,7 @@ functions_mode_check(S, Info) -> ?line {ok, V} = xref:q(S, "X + L + B + U"), %% X, L, B and U are disjoint. - ?line {ok, []} = + ?line {ok, []} = xref:q(S, "X * L + X * B + X * U + L * B + L * U + B * U"), %% V = UU + XU + LU, @@ -2577,11 +2593,11 @@ functions_mode_check(S, Info) -> ?line {Local, Exported} = info(Info, no_functions), ?line LX = Local+Exported, - ?line {ok, LXs} = xref:q(S, 'Extra = _:module_info/"(0|1)" + LM, + ?line {ok, LXs} = xref:q(S, 'Extra = _:module_info/"(0|1)" + LM, # (F - Extra)'), ?line true = LX =:= LXs, - ?line {LocalCalls, ExternalCalls, UnresCalls} = + ?line {LocalCalls, ExternalCalls, UnresCalls} = info(Info, no_function_calls), ?line LEU = LocalCalls + ExternalCalls + UnresCalls, ?line {ok, LEU} = xref:q(S, "# LC + # XC"), @@ -2635,7 +2651,7 @@ check_count(S) -> %% {ok, A} = xref:q(S, 'A'), {ok, M} = xref:q(S, 'AM'), - {ok, _} = xref:q(S, + {ok, _} = xref:q(S, "Extra := _:module_info/\"(0|1)\" + LM"), %% info/1: @@ -2670,7 +2686,7 @@ check_count(S) -> ok. info_module([M | Ms], S) -> - {ok, NoCalls} = per_module("T = (E | ~p : Mod), # (XLin) T + # (LLin) T", + {ok, NoCalls} = per_module("T = (E | ~p : Mod), # (XLin) T + # (LLin) T", M, S), {ok, NoFunCalls} = per_module("# (E | ~p : Mod)", M, S), {ok, NoXCalls} = per_module("# (XC | ~p : Mod)", M, S), @@ -2719,14 +2735,14 @@ start(Server) -> end. add_erts_code_path(KernelPath) -> - VersionDirs = + VersionDirs = filelib:is_dir( filename:join( [code:lib_dir(), lists:flatten( ["kernel-", - [X || - {kernel,_,X} <- + [X || + {kernel,_,X} <- application_controller:which_applications()]])])), case VersionDirs of true -> @@ -2746,5 +2762,5 @@ add_erts_code_path(KernelPath) -> [KernelPath] end end. - - + + diff --git a/lib/tools/test/xref_SUITE_data/read/read.erl b/lib/tools/test/xref_SUITE_data/read/read.erl index 4a0cc280c3..19694c9e25 100644 --- a/lib/tools/test/xref_SUITE_data/read/read.erl +++ b/lib/tools/test/xref_SUITE_data/read/read.erl @@ -106,13 +106,13 @@ funfuns() -> apply(m,f,a), % {m,f,-1} 3(a), % {'$M_EXPR','$F_EXPR',1} apply(3,[a]), % {'$M_EXPR','$F_EXPR',1} - + %% POS12=POS11+8 apply(A, A), % number of arguments is not known, {'$M_EXPR','$F_EXPR',-1} Args0 = [list], Args = [a | Args0], % number of arguments is known apply(A, Args), % {'$M_EXPR','$F_EXPR',2} - apply(m3, f3, Args), % + apply(m3, f3, Args), % NotArgs = [is_not, a | list], % number of arguments is not known apply(A, NotArgs), % {'$M_EXPR','$F_EXPR',-1} apply(m4, f4, NotArgs), % {m4,f4,-1} @@ -125,7 +125,7 @@ funfuns() -> bi() when length([]) > 17 -> foo:module_info(), module_info(), - A = tjo, + A = true andalso tjo , t:foo(A), case true of true when integer(1) -> @@ -133,7 +133,7 @@ bi() when length([]) > 17 -> false -> X = flopp end, - X == A; + self() ! X == -A orelse false; bi() -> %% POS14=POS13+18 Z = fun(Y) -> Y end, @@ -159,7 +159,7 @@ bi() -> D + E + F. %bi() -> % %% POS15=POS14+13 -% try +% try % foo:t(), % bar:t() % of @@ -169,7 +169,7 @@ bi() -> % foo:t() % catch % {'EXIT',_} -> bar:t() -% end. +% end. local() -> true. diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk index 13cf5af9f5..abe9a804f0 100644 --- a/lib/tools/vsn.mk +++ b/lib/tools/vsn.mk @@ -1,19 +1,19 @@ # This is an -*-makefile-*- file. # %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2009. All Rights Reserved. -# +# +# Copyright Ericsson AB 1997-2010. 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% -TOOLS_VSN = 2.6.5.1 +TOOLS_VSN = 2.6.6 |