Find Undefined Functions and Data

DESCRIPTION:

Look for the use of undefined functions and data in S-PLUS or R source files. The names of all undefined items and the names of the files and functions where they are referenced are returned.

USAGE:

unresolvedGlobalReferences(dir, files=<<see below>>,
                           referenceList, definedHere=character(),
                           expressions=1200, ignore.working.database=T)
globalAssignments(files)
globalReferences(files=character(), expr=NULL, cacheFrame=NULL,
                 name="<root>", just.assigned.name=NULL,
                 outputCacheFrame=NULL, expressions=1200)

REQUIRED ARGUMENTS:

dir
a character vector containing the directory paths to be searched for S-PLUS or R source files. All files ending with .q, .ssc, .S or .R found in the specified directories will be searched for unresolved functions and references. The files= argument is ignored if this argument is given.
files
a character vector containing the names of files to be examined for unresolved functions and references. A file name must include the path to the file unless the file is in the current working directory. The dir= argument is ignored if this argument is given.

OPTIONAL ARGUMENTS:

definedHere
character vector of names of objects which are known to be undefined and will not be reported as unresolved in the return value. This is useful during development if you have a list of functions known to be in another package.
expressions
the maximum depth to which expressions can be nested. These functions are recursive and can easily exceed the usual nesting limit given by options("expressions").
ignore.working.database
a logical value indicating whether or not the working database will be searched to find unresolved references. By default, the working database is ignored.
referenceList
a list of character vectors where each vector contains names of referenced objects. The returned value will have references to known functions removed. The dir= and files= arguments must not be supplied when this argument is given.

VALUE:

unresolvedGlobalReferences returns a list of named character vectors, where each list element is a vector of undefined references in a function, and the element's name gives the name of the function. The name of each list element is encoded to contain the source file name and the function in that file, or a sequence of functions if the function is nested within functions, having this format:
"filename#functionName#subfunctionName#subsubfunctionName"
The last function in the sequence contains the undefined references. If an inner function is not given a name, as in
sapply(x, function(xi)length(xi))
then it gets called <anonymous-n> with a different n for each unnamed function defined in a given function.

For example, the following list element shows that the first unnamed function in the function newFunc1 contains undefined references.
$"/tmp/testdir/newFunctions.q#newFunc1#<anonymous-1>":
[1] "n" "sep"

If a function uses the <<- operator the output entry for that function will have an attribute called "uses <<-". The double-arrow operator means different things in R and S-PLUS and such code is not portable.

If a function uses the :: or ::: namespace operators the output entry for that function will have an attribute called "uses explicit namespace" listing all the usages in the function. S-PLUS does not support namespaces and :: and ::: functions in the pkgutils library will ignore the namespace in namespace::name.

unresolvedGlobalReferences returns an empty list if no undefined objects (or other problems) are found.

The following functions are called by unresolvedGlobalReferences, and may not be useful to most users.

The function globalAssignments returns a character vector containing all global assignments found in the given source file(s).

The function globalReferences returns a list of named character vectors containing all global references found in the given source file(s). There is a list element for each function defined in the source files. The format of the list element names is the same as described above for the function unresolvedGlobalReferences .

DETAILS:

The function unresolvedGlobalReferences is helpful when porting R packages to S-PLUS in order to find problems involving missing R functions or lexical scoping. It searches either all source files in the specified directory if the dir argument is specified or the files included in the files argument.

Note how the names of the files and functions in the files are encoded in the output list: file#func#subfunc#subsubfunc, but line numbers are not given. To find the anonymous functions look for the word 'function' in your source file.

In order to analyze R source code files containing S-PLUS code written for R, use set.parse.mode("R"). Parsing in R mode allows underscores in names and treats 10 as a numeric instead of an integer, although there are still some things the parser rejects (like assigning to the variables T and F).

The contents of a non-S-PLUS clauses are ignored when either is.R() or !is.R() is used in if statements.

The name of the namespace in namespace:::func or namespace::func is ignored, but ::: and :: will be reported as missing. The names of the non-functions in formulae are also ignored as those generally are found at run time in a data= argument, but the subset= and weights= arguments in modeling and trellis functions are not ignored, as those are evaluated with local=data also, just like the formula.

SEE ALSO:

.
See the Guide to S-PLUS Packages manual for more details.

EXAMPLES:

# This example shows that the function kahanAddNext, called by
# kahanSum, is not defined in the file kahanSum.q.
z <- unresolvedGlobalReferences(files = file.path(getenv("SHOME"),
        "samples/kahanSum/kahanSum.q"))
z

# This example illustrates problems with missing functions
# and lexical scoping (in the sapply call).
newFunc1 <- function(x, sep) {
        tmp <- unknownFunc1(x)
        if(is.R())
                tmp <- `some_R_func`(x)
        else
                tmp <- unknownFunc2(x)
        if(FALSE)
                tmp <- unknownFunc3(x)
        tmp <- newFunc2(x)
        sapply(tmp, function(tmpi)
        paste(tmpi, n, sep = sep))
}
newFunc2 <- function(x) log(x)
testdir <- tempfile()
mkdir(testdir)
file1 <- dump("newFunc1", file.path(testdir, "newFunc1.q"))
file2 <- dump("newFunc2", file.path(testdir, "newFunc2.q"))
unresolvedGlobalReferences(dir=testdir, definedHere=c("unknownFunc1"))
unresolvedGlobalReferences(files=file1, ignore.working.database=F)
globalAssignments(files=file1)
globalReferences(files=file2)
rmdir(testdir)
# Variables used in the default values of functions may be incorrectly
# returned as undefined when defined in the body of the function.
newFunc3 <- function (x, n = length(u))
{
        u <- unique(x)
        list(x=x, u=u, n=n)
}
testdir <- tempfile()
mkdir(testdir)
file3 <- dump("newFunc3", file.path(testdir, "newFunc3.q"))
# u is incorrectly reported as unresolved
unresolvedGlobalReferences(files=file3)
rmdir(testdir)