Brian Wolff has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/393537 )

Change subject: Fix remaining tests (mostly phpcs)
......................................................................


Fix remaining tests (mostly phpcs)

Change-Id: Ic802e332ab0fbabc3434b308a41353eaafbab69b
---
M .phpcs.xml
M src/GenericSecurityCheckPlugin.php
M src/MediaWikiSecurityCheckPlugin.php
M src/PreTaintednessVisitor.php
M src/SecurityCheckPlugin.php
M src/TaintednessBaseVisitor.php
M src/TaintednessVisitor.php
7 files changed, 536 insertions(+), 89 deletions(-)



diff --git a/.phpcs.xml b/.phpcs.xml
index b7513f7..d5331bd 100644
--- a/.phpcs.xml
+++ b/.phpcs.xml
@@ -3,6 +3,7 @@
                <rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
                <exclude 
name="MediaWiki.NamingConventions.PrefixedGlobalFunctions.wfPrefix"/>
                <exclude name="MediaWiki.Usage.ScalarTypeHintUsage.Found"/>
+               <exclude 
name="MediaWiki.Commenting.FunctionComment.MissingParamComment"/>
        </rule>
                <file>.</file>
                <arg name="bootstrap" 
value="./vendor/mediawiki/mediawiki-codesniffer/utils/bootstrap-ci.php"/>
diff --git a/src/GenericSecurityCheckPlugin.php 
b/src/GenericSecurityCheckPlugin.php
index 51f9684..0d21534 100644
--- a/src/GenericSecurityCheckPlugin.php
+++ b/src/GenericSecurityCheckPlugin.php
@@ -15,6 +15,9 @@
  */
 class GenericSecurityCheckPlugin extends SecurityCheckPlugin {
 
+       /**
+        * @inheritDoc
+        */
        protected function getCustomFuncTaints() : array {
                return [];
        }
diff --git a/src/MediaWikiSecurityCheckPlugin.php 
b/src/MediaWikiSecurityCheckPlugin.php
index bc6c4a4..75d5166 100644
--- a/src/MediaWikiSecurityCheckPlugin.php
+++ b/src/MediaWikiSecurityCheckPlugin.php
@@ -6,6 +6,9 @@
 
 class MediaWikiSecurityCheckPlugin extends SecurityCheckPlugin {
 
+       /**
+        * @inheritDoc
+        */
        protected function getCustomFuncTaints() : array {
                return [
                        // '\Message::__construct' => 
SecurityCheckPlugin::YES_TAINT,
diff --git a/src/PreTaintednessVisitor.php b/src/PreTaintednessVisitor.php
index 70c0172..46f0f83 100644
--- a/src/PreTaintednessVisitor.php
+++ b/src/PreTaintednessVisitor.php
@@ -5,12 +5,35 @@
 use ast\Node\Decl;
 use Phan\Debug;
 
+/**
+ * Class for visiting any nodes we want to handle in pre-order.
+ *
+ * Unlike TaintednessVisitor, this is solely used to set taint
+ * on variable objects, and not to determine the taint of the
+ * current node, so this class does not return anything.
+ */
 class PreTaintednessVisitor extends TaintednessBaseVisitor {
 
+       /**
+        * Handle any node not otherwise handled.
+        *
+        * Currently a no-op.
+        *
+        * @param Node $node
+        */
        public function visit( Node $node ) {
-               // no-op
        }
 
+       /**
+        * Visit a foreach loop
+        *
+        * This is done in pre-order so that we can handle
+        * the loop condition prior to determine the taint
+        * of the loop variable, prior to evaluating the
+        * loop body.
+        *
+        * @param Node $node
+        */
        public function visitForeach( Node $node ) {
                // TODO: Could we do something better here detecting the array
                // type
@@ -44,17 +67,29 @@
                        // getVariable can throw an IssueException if var 
doesn't exist.
                        $this->debug( __METHOD__, "Exception " . get_class( $e 
) . $e->getMessage() . "" );
                }
-
-               // The foreach as a block cannot be tainted.
-               return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * @see visitMethod
+        * @param Decl $node
+        * @return void Just has a return statement in case visitMethod changes
+        */
        public function visitFuncDecl( Decl $node ) {
                return $this->visitMethod( $node );
        }
 
        /**
+        * Set the taintedness of parameters to method/function.
+        *
+        * Parameters that are ints (etc) are clearly safe so
+        * this marks them as such. For other parameters, it
+        * creates a map between the function object and the
+        * parameter object so if anyone later calls the method
+        * with a dangerous argument we can determine if we need
+        * to output a warning.
+        *
         * Also handles FuncDecl
+        * @param Decl $node
         */
        public function visitMethod( Decl $node ) {
                // var_dump( __METHOD__ ); Debug::printNode( $node );
diff --git a/src/SecurityCheckPlugin.php b/src/SecurityCheckPlugin.php
index 0eb4490..94d6b5b 100644
--- a/src/SecurityCheckPlugin.php
+++ b/src/SecurityCheckPlugin.php
@@ -44,20 +44,12 @@
        const YES_EXEC_TAINT = 2040;
 
        /**
-        * @param CodeBase $code_base
-        * The code base in which the node exists
+        * Called on every node in the AST in post-order
         *
-        * @param Context $context
-        * The context in which the node exits. This is
-        * the context inside the given node rather than
-        * the context outside of the given node
-        *
-        * @param Node $node
-        * The php-ast Node being analyzed.
-        *
-        * @param Node $node
-        * The parent node of the given node (if one exists).
-        *
+        * @param CodeBase $code_base The code base in which the node exists
+        * @param Context $context The context in which the node exits.
+        * @param Node $node The php-ast Node being analyzed.
+        * @param Node $parent_node The parent node of the given node (if one 
exists).
         * @return void
         */
        public function analyzeNode(
@@ -66,19 +58,32 @@
                Node $node,
                Node $parent_node = null
        ) {
-       // echo __METHOD__ . ' ' .\ast\get_kind_name($node->kind) . " (Parent: 
" . ($parent_node ? \ast\get_kind_name($parent_node->kind) : "N/A") . ")\n";
                $oldMem = memory_get_peak_usage();
-               ( new TaintednessVisitor( $code_base, $context, $this ) )(
-                       $node
-               );
+               // This would also return the taint of the current node,
+               // but we don't need that here so we discard the return value.
+               $visitor = new TaintednessVisitor( $code_base, $context, $this 
);
+               $visitor( $node );
                $newMem = memory_get_peak_usage();
                $diff = floor( ( $newMem - $oldMem ) / ( 1024 * 1024 ) );
                if ( $diff > 10 ) {
-                       echo "Memory Spike! " . $context . " " 
.\ast\get_kind_name( $node->kind ) .
-                       " diff=$diff MB; cur=" . floor( ( memory_get_usage() / 
( 1024 * 1024 ) ) ) . " MB\n";
+                       $cur = floor( ( memory_get_usage() / ( 1024 * 1024 ) ) 
);
+                       $visitor->debug( __METHOD__, "Memory Spike! " . 
\ast\get_kind_name( $node->kind ) .
+                               " diff=$diff MB; cur=$cur MB\n"
+                       );
                }
        }
 
+       /**
+        * Called on every node in the ast, but in pre-order
+        *
+        * We only need this for a couple things, namely
+        * structural elements that cause a new variable to be
+        * declared (e.g. method declarations, foreach loops)
+        *
+        * @param CodeBase $code_base
+        * @param Context $context
+        * @param Node $node
+        */
        public function preAnalyzeNode( CodeBase $code_base, Context $context, 
Node $node ) {
                ( new PreTaintednessVisitor( $code_base, $context, $this ) )( 
$node );
        }
diff --git a/src/TaintednessBaseVisitor.php b/src/TaintednessBaseVisitor.php
index 14d87e8..d04cd3b 100644
--- a/src/TaintednessBaseVisitor.php
+++ b/src/TaintednessBaseVisitor.php
@@ -17,13 +17,23 @@
 use Phan\Library\Set;
 use Phan\Exception\IssueException;
 
+/**
+ * Base class for the Tainedness visitor subclass. Mostly contains
+ * utility methods.
+ */
 abstract class TaintednessBaseVisitor extends AnalysisVisitor {
 
        /** @var SecurityCheckPlugin */
        protected $plugin;
 
+       /** @var null|string|bool|resource filehandle to output debug messages 
*/
        private $debugOutput = null;
 
+       /**
+        * @param CodeBase $code_base
+        * @param Context $context
+        * @param SecurityCheckPlugin $plugin The instance of the plugin we're 
using
+        */
        public function __construct(
                CodeBase $code_base,
                Context $context,
@@ -81,7 +91,16 @@
        }
 
        /**
-        * It is assumed you already checked that right is tainted in some way.
+        * Merge the info on original cause of taint to left variable
+        *
+        * If you have something like $left = $right, merge any information
+        * about what tainted $right into $left as $right's taint may now
+        * have tainted $left (Or may not if the assingment is in a branch
+        * or its not a local variable).
+        *
+        * @note It is assumed you already checked that right is tainted in 
some way.
+        * @param TypedElementInterface $left (LHS-ish variable)
+        * @param TypedElementInterface $right (RHS-ish variable)
         */
        protected function mergeTaintError( TypedElementInterface $left, 
TypedElementInterface $right ) {
                if ( !property_exists( $left, 'taintedOriginalError' ) ) {
@@ -102,8 +121,13 @@
         * @param int $taintedness One of the class constants
         * @param bool $override Override taintedness or just take max.
         */
-       protected function setTaintedness( TypedElementInterface $variableObj, 
int $taintedness, $override = true ) {
-               // $this->debug( __METHOD__, "begin for \$" . 
$variableObj->getName() . " <- $taintedness (override=$override)" );
+       protected function setTaintedness(
+               TypedElementInterface $variableObj,
+               int $taintedness,
+               $override = true
+       ) {
+               // $this->debug( __METHOD__, "begin for \$" . 
$variableObj->getName()
+                       // . " <- $taintedness (override=$override)" );
 
                assert( $taintedness >= 0, $taintedness );
 
@@ -115,12 +139,12 @@
                if ( property_exists( $variableObj, 'taintednessHasOuterScope' )
                        || !( $this->context->getScope() instanceof 
FunctionLikeScope )
                ) {
-// $this->debug( __METHOD__, "\$" . $variableObj->getName() . " has outer 
scope - " . get_class( $this->context->getScope()) . "" );
+// $this->debug( __METHOD__, "\$" . $variableObj->getName() . " has outer 
scope - "
+// . get_class( $this->context->getScope()) . "" );
                        // If the current context is not a FunctionLikeScope, 
then
                        // it might be a class, or an if branch, or global. In 
any case
                        // its probably a non-local variable (or in the if 
case, code
                        // that may not be executed).
-                       //
 
                        if ( !property_exists( $variableObj, 
'taintednessHasOuterScope' )
                                && ( $this->context->getScope() instanceof 
BranchScope )
@@ -146,7 +170,8 @@
                                        $variableObjLinks = 
$variableObj->taintedMethodLinks ?? new Set;
                                        $variableObj->taintedMethodLinks = 
$methodLinks->union( $variableObjLinks );
                                        $parentVarObj->taintedMethodLinks =& 
$variableObj->taintedMethodLinks;
-                                       $combinedOrig = ( 
$variableObj->taintedOriginalError ?? '' ) . ( 
$parentVarObj->taintedOriginalError ?? '' );
+                                       $combinedOrig = ( 
$variableObj->taintedOriginalError ?? '' )
+                                               . ( 
$parentVarObj->taintedOriginalError ?? '' );
                                        if ( strlen( $combinedOrig ) > 254 ) {
                                                $this->debug( __METHOD__, "Too 
long original error! $variableObj" );
                                                $combinedOrig = substr( 
$combinedOrig, 0, 250 ) . '...';
@@ -185,7 +210,9 @@
 
                        if ( strlen( $variableObj->taintedOriginalError ) > 254 
) {
                                $this->debug( __METHOD__, "Too long original 
error! $variableObj" );
-                               $variableObj->taintedOriginalError = substr( 
$variableObj->taintedOriginalError, 0, 250 ) . '...';
+                               $variableObj->taintedOriginalError = substr(
+                                       $variableObj->taintedOriginalError, 0, 
250
+                               ) . '...';
                        }
                }
        }
@@ -206,6 +233,7 @@
        /**
         * This is also for methods and other function like things
         *
+        * @param FunctionInterface $func What function/method to look up
         * @return int[] Array with "overall" key, and numeric keys.
         *   The overall key specifies what taint the function returns
         *   irrespective of its arguments. The numeric keys are how
@@ -274,7 +302,14 @@
        }
 
        /**
+        * Given a type, determine what type of taint
+        *
+        * e.g. Integers are probably untainted since its hard to do evil
+        * with them, but mark strings as unknown since we don't know.
+        *
         * Only use as a fallback
+        * @param UnionType $types The types
+        * @return int The taint in question
         */
        protected function getTaintByReturnType( UnionType $types ) : int {
                $taint = SecurityCheckPlugin::NO_TAINT;
@@ -314,6 +349,10 @@
        }
 
        /**
+        * Get the built in taint of a function/method
+        *
+        * This is used for when people special case if a function is tainted.
+        *
         * @param FullyQualifiedFunctionLikeName $fqsen Function to check
         * @return null|array Null if no info, otherwise the taint for the 
function
         */
@@ -325,9 +364,14 @@
                return $taint;
        }
 
+       /**
+        * Get name of current method (for debugging purposes)
+        *
+        * @return string Name of method or "[no method]"
+        */
        protected function getCurrentMethod() {
                return $this->context->isInFunctionLikeScope() ?
-                       $this->context->getFunctionLikeFQSEN() : '[no method]';
+                       (string)$this->context->getFunctionLikeFQSEN() : '[no 
method]';
        }
 
        /**
@@ -338,7 +382,7 @@
         *
         * FIXME maybe it should try and turn into phan object.
         * @param Mixed $expr An expression from the AST tree.
-        * @return int
+        * @return int The taint
         */
        protected function getTaintedness( $expr ) : int {
                $type = gettype( $expr );
@@ -367,6 +411,12 @@
                }
        }
 
+       /**
+        * Give an AST node, find its taint
+        *
+        * @param Node $node
+        * @return int The taint
+        */
        protected function getTaintednessNode( Node $node ) : int {
                // Debug::printNode( $node );
                $r = ( new TaintednessVisitor( $this->code_base, 
$this->context, $this->plugin ) )(
@@ -376,6 +426,12 @@
                return $r;
        }
 
+       /**
+        * Given a phan object (not method/function) find its taint
+        *
+        * @param TypedElementInterface $variableObj
+        * @return int The taint
+        */
        protected function getTaintednessPhanObj( TypedElementInterface 
$variableObj ) : int {
                $taintedness = SecurityCheckPlugin::UNKNOWN_TAINT;
                if ( $variableObj instanceof FunctionInterface ) {
@@ -387,12 +443,19 @@
                } else {
                        $type = $variableObj->getUnionType();
                        $taintedness = $this->getTaintByReturnType( $type );
-                       // echo $this->dbgInfo() . " \$" . 
$variableObj->getName() . " first sight. taintedness set to $taintedness due to 
type $type\n";
+                       // $this->debug( " \$" . $variableObj->getName() . " 
first sight."
+                       // . " taintedness set to $taintedness due to type 
$type\n";
                }
                assert( is_int( $taintedness ) && $taintedness >= 0 );
                return $taintedness;
        }
 
+       /**
+        * Quick wrapper to get the ContextNode for a node
+        *
+        * @param Node $node
+        * @return ContextNode
+        */
        protected function getCtxN( Node $node ) {
                return new ContextNode(
                        $this->code_base,
@@ -418,6 +481,10 @@
         *
         * @suppress PhanTypeMismatchForeach No idea why its confused
         * @suppress PhanUndeclaredMethod it checks method_exists()
+        * @param Node $node AST node in question
+        * @param bool $all Whether or not to only include objects that 
directly correspond
+        *   In particular, whether or not to include Method objects for method 
calls.
+        * @return Array Array of various phan objects corresponding to $node
         */
        protected function getPhanObjsForNode( Node $node, $all = false ) {
                $cn = $this->getCtxN( $node );
@@ -440,13 +507,25 @@
                                                        }
                                                }
                                        } catch ( IssueException $e ) {
-                                               $this->debug( __METHOD__, 
"Cannot determine property or var name [1] (Maybe don't know what class) - " . 
$e->getIssueInstance() );
+                                               $this->debug( __METHOD__,
+                                                       "Cannot determine 
property or var " .
+                                                       "name [1] (Maybe don't 
know what class) - "
+                                                       . $e->getIssueInstance()
+                                               );
                                                return [];
                                        } catch ( Exception $e ) {
-                                               $this->debug( __METHOD__, 
"Cannot determine property or var name [2] (Maybe don't know what class) - " . 
get_class( $e ) . $e->getMessage() );
+                                               $this->debug( __METHOD__,
+                                                       "Cannot determine 
property or var " .
+                                                       "name [2] (Maybe don't 
know what class) - "
+                                                       . get_class( $e ) . 
$e->getMessage() );
                                                return [];
                                        }
-                                       $this->debug( __METHOD__, "Cannot 
determine property [3] (Maybe don't know what class) - " . ( method_exists( $e, 
'getIssueInstance' ) ? $e->getIssueInstance() : get_class( $e ) . 
$e->getMessage() ) );
+                                       $this->debug( __METHOD__, "Cannot 
determine " .
+                                               "property [3] (Maybe don't know 
what class) - " .
+                                               ( method_exists( $e, 
'getIssueInstance' )
+                                               ? $e->getIssueInstance()
+                                               : get_class( $e ) . 
$e->getMessage() )
+                                       );
                                        return [];
                                }
                        case \ast\AST_VAR:
@@ -568,7 +647,9 @@
                                // Debug::printNode( $node );
                                // This should really be a visitor that 
recurses into
                                // things.
-                               echo __METHOD__ . $this->dbgInfo() . " FIXME 
unhandled case" . \ast\get_kind_name( $node->kind ) . "\n";
+                               $this->debug( __METHOD__, "FIXME unhandled case"
+                                       . \ast\get_kind_name( $node->kind ) . 
"\n"
+                               );
                                return [];
                }
        }
@@ -591,12 +672,18 @@
         * later, we can traceback anything it might affect
         *
         * @suppress PhanTypeMismatchProperty
+        * @param Variable $param The variable object for the parameter
+        * @param FunctionInterface $func The function/method in question
+        * @param int $i Which argument number is $param
         */
        protected function linkParamAndFunc( Variable $param, FunctionInterface 
$func, int $i ) {
                if ( !( $param instanceof Variable ) ) {
                        // Probably a PassByReferenceVariable.
                        // TODO, handling of PassByReferenceVariable probably 
wrong here.
-                       $this->debug( __METHOD__, "Called on a non-variable \$" 
. $param->getName() . " of type " . get_class( $param ) . ". May be handled 
wrong." );
+                       $this->debug( __METHOD__, "Called on a non-variable \$"
+                               . $param->getName() . " of type " . get_class( 
$param )
+                               . ". May be handled wrong."
+                       );
                }
                if ( !property_exists( $func, 'taintedVarLinks' ) ) {
                        $func->taintedVarLinks = [];
@@ -618,7 +705,22 @@
                }
        }
 
-       protected function mergeTaintDependencies( TypedElementInterface $lhs, 
TypedElementInterface $rhs ) {
+       /**
+        * Given a LHS and RHS make all the methods that can set RHS also for 
LHS
+        *
+        * Given 2 variables (e.g. $lhs = $rhs ), see to it that any 
function/method
+        * which we marked as being able to set the value of rhs, is also marked
+        * as being able to set the value of lhs.
+        *
+        * This also merges the information on what line caused the taint.
+        *
+        * @param TypedElementInterface $lhs Source of method list
+        * @param TypedElementInterface $rhs Destination of merged method list
+        */
+       protected function mergeTaintDependencies(
+               TypedElementInterface $lhs,
+               TypedElementInterface $rhs
+       ) {
                $taintLHS = $this->getTaintedness( $lhs );
                $taintRHS = $this->getTaintedness( $rhs );
                /********************
@@ -629,7 +731,8 @@
                        $taintLHS < SecurityCheckPlugin::PRESERVE_TAINT ||
                        $taintRHS !== SecurityCheckPlugin::PRESERVE_TAINT
                ) {
-                       $this->debug( __METHOD__, "FIXME merging dependencies 
where LHS and RHS are not both preserved taint. lhs=$taintLHS; rhs=$taintRHS" );
+                       $this->debug( __METHOD__, "FIXME merging dependencies 
where" .
+                               " LHS and RHS are not both preserved taint. 
lhs=$taintLHS; rhs=$taintRHS" );
                } */
 
                if ( $taintRHS & SecurityCheckPlugin::YES_EXEC_TAINT ) {
@@ -665,11 +768,15 @@
        }
 
        /**
+        * Mark any function setting a specific variable as EXEC taint
+        *
         * If you do something like echo $this->foo;
         * This method is called to make all things that set $this->foo
         * as TAINT_EXEC.
         *
-        * TODO delete all dependencies as no longer needed.
+        * @todo delete all dependencies as no longer needed (or are they?)
+        * @param TypedElementInterface $var The variable in question
+        * @param int $taint What taint to mark them as.
         */
        protected function markAllDependentMethodsExec(
                TypedElementInterface $var,
@@ -691,7 +798,8 @@
                        $paramTaint = [ 'overall' => 
SecurityCheckPlugin::NO_TAINT ];
                        foreach ( $paramInfo as $i => $_ ) {
                                $paramTaint[$i] = $taint;
-                               // $this->debug( __METHOD__ , "Setting method 
$method arg $i as $taint due to depenency on $var" );
+                               // $this->debug( __METHOD__ , "Setting method 
$method" .
+                                       // " arg $i as $taint due to depenency 
on $var" );
                        }
                        $this->setFuncTaint( $method, $paramTaint );
                }
@@ -710,7 +818,13 @@
        /**
         * This happens when someone call foo( $evilTaintedVar );
         *
-        * It makes sure that anything that foo sets will become tainted.
+        * It makes sure that any variable that the function foo() sets takes on
+        * the taint of the supplied argument.
+        *
+        * @todo FIXME this needs to handle different types of taint.
+        *
+        * @param FunctionInterface $method The function or method in question
+        * @param int $i The number of the argument in question.
         */
        protected function markAllDependentVarsYes( FunctionInterface $method, 
int $i ) {
                if ( $method->isInternal() ) {
@@ -724,11 +838,9 @@
                        return;
                }
                $oldMem = memory_get_peak_usage();
-               // echo __METHOD__ . $this->dbgInfo() . "Setting all vars 
depending on $method as tainted\n";
                foreach ( $method->taintedVarLinks[$i] as $var ) {
                        $curVarTaint = $this->getTaintedness( $var );
                        $newTaint = $this->mergeAddTaint( $curVarTaint, 
SecurityCheckPlugin::YES_TAINT );
-                       // echo __METHOD__ . $this->dbgInfo() . "Setting $var 
as $newTaint due to dependency on $method\n";
                        $this->setTaintedness( $var, $newTaint );
                }
                // Maybe delete links??
@@ -740,7 +852,9 @@
        }
 
        /**
-        * @param int taint
+        * Are any of the YES (i.e HTML_TAINT) taint flags set
+        *
+        * @param int $taint
         * @return bool If the variable has known (non-execute taint)
         */
        protected function isYesTaint( $taint ) {
@@ -748,7 +862,9 @@
        }
 
        /**
-        * @param int taint
+        * Does the taint have one of EXEC flags set
+        *
+        * @param int $taint
         * @return bool If the variable has any exec taint
         */
        protected function isExecTaint( $taint ) {
@@ -771,6 +887,10 @@
         * Convert exec to yes taint
         *
         * Special flags like UNKNOWN or INAPLICABLE are discarded.
+        * Any YES flags are also discarded
+        *
+        * @param int $taint The taint in question
+        * @return int The taint with all the EXEC to yes, and all other flags 
off
         */
        protected function execToYesTaint( int $taint ) : int {
                return ( $taint & SecurityCheckPlugin::EXEC_TAINT ) >> 1;
@@ -795,12 +915,14 @@
 
        /**
         * Is taint likely a false positive
-        * @param $taint
         *
         * Taint is a false positive if it has the unknown flag but
         * none of the yes flags.
+        *
+        * @param int $taint
+        * @return bool
         */
-       protected function isLikelyFalsePositive( $taint ) {
+       protected function isLikelyFalsePositive( int $taint ) : bool {
                return ( $taint & SecurityCheckPlugin::UNKNOWN_TAINT ) !== 0
                        && ( $taint & SecurityCheckPlugin::YES_TAINT ) === 0;
        }
@@ -856,8 +978,9 @@
         *
         * @param Mixed $node Either a Node or a string, int, etc. The 
expression
         * @param int $taintedness The taintedness in question
-        * @param FunctionInterface $func The function/method we are in.
+        * @param FunctionInterface $curFunc The function/method we are in.
         * @return Array numeric keys for each parameter taint and 'overall' key
+        * @suppress PhanTypeMismatchForeach
         */
        protected function matchTaintToParam(
                $node,
@@ -913,7 +1036,6 @@
                }
                $paramTaint['overall'] = ( $otherTaint | $taintRemaining ) &
                        $taintedness;
-               // $this->debug( __METHOD__, " otherTaint $otherTaint, 
taintRemaining $taintRemaining, taintedness = $taintedness, overall " . 
$paramTaint['overall'] );
                return $paramTaint;
        }
 
@@ -923,11 +1045,15 @@
         * @param string $method __METHOD__ in question
         * @param string $msg debug message
         */
-       protected function debug( $method, $msg ) {
-               if ( !$this->debugOutput ) {
+       public function debug( $method, $msg ) {
+               if ( $this->debugOutput === null ) {
                        $errorOutput = getenv( "SECCHECK_DEBUG" );
-                       if ( $errorOutput ) {
+                       if ( $errorOutput && $errorOutput !== '-' ) {
                                $this->debugOutput = fopen( $errorOutput, "w" );
+                       } elseif ( $errorOutput === '-' ) {
+                               $this->debugOutput = '-';
+                       } else {
+                               $this->debugOutput = false;
                        }
                }
                $line = $method . "\33[1m" . $this->dbgInfo() . " \33[0m" . 
$msg .     "\n";
@@ -942,9 +1068,12 @@
        }
 
        /**
-        * Make sure func taint is well formed
+        * Make sure func taint array is well formed
         *
-        * @param array the taint of a function
+        * @warning Will cause an assertion failure if not well formed.
+        *
+        * @param array $taint the taint of a function
+        * @return void
         */
        protected function checkFuncTaint( array $taint ) {
                assert(
diff --git a/src/TaintednessVisitor.php b/src/TaintednessVisitor.php
index 35428da..aa4b54c 100644
--- a/src/TaintednessVisitor.php
+++ b/src/TaintednessVisitor.php
@@ -37,25 +37,31 @@
        public function visit( Node $node ) : int {
                // This method will be called on all nodes for which
                // there is no implementation of it's kind visitor.
-               //
+
                // To see what kinds of nodes are passing through here,
                // you can run `Debug::printNode($node)`.
-       /*      echo __METHOD__ . ' ';
-               //var_dump( $this->context );
-               echo ' ';
-                Debug::printNode($node); */
-               # echo __METHOD__  . $this->dbgInfo() . " setting unknown taint 
for " . \ast\get_kind_name( $node->kind ) . "\n";
                # Debug::printNode( $node );
                $this->debug( __METHOD__, "unhandled case " . 
\ast\get_kind_name( $node->kind ) );
                return SecurityCheckPlugin::UNKNOWN_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitFuncDecl( Decl $node ) : int {
                return $this->visitMethod( $node );
        }
 
        /**
+        * Visit a method decleration
+        *
+        * At this point we should have already hit a return statement
+        * so if we haven't yet, mark this function as no taint.
+        *
         * Also handles FuncDecl
+        * @param Decl $node
+        * @return int Taint
         */
        public function visitMethod( Decl $node ) : int {
                $method = $this->context->getFunctionLikeInScope( 
$this->code_base );
@@ -78,8 +84,6 @@
                        // until later, so setting this to NO_TAINT here might 
miss
                        // some issues in the inbetween period.
                        $this->setFuncTaint( $method, [ 'overall' => 
SecurityCheckPlugin::NO_TAINT ] );
-
-                       // $this->debug( __METHOD__, $method . " is set to no 
taint due to lack of return and side effects." );
                }
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
@@ -88,100 +92,189 @@
        // separate methods so we can use visit to output debugging
        // for anything we miss.
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitStmtList( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitArgList( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitParamList( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
        /**
-        * Params should be handled in PreTaintednessVisitor
+        * @note Params should be handled in PreTaintednessVisitor
+        * @param Node $node
+        * @return int Taint
         */
        public function visitParam( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitClass( Decl $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitClassConstDecl( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitIf( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitThrow( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
-       // Actual property decleration is PropElem
+       /**
+        * Actual property decleration is PropElem
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitPropDecl( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitConstElem( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitUse( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitBreak( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitContinue( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitGoto( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitCatch( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitNamespace( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitSwitch( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitSwitchCase( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitWhile( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitUnset( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitTry( Node $node ) : int {
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitAssignOp( Node $node ) : int {
                return $this->visitAssign( $node );
        }
 
        /**
         * Also handles visitAssignOp
+        *
+        * @param Node $node
+        * @return int Taint
         */
        public function visitAssign( Node $node ) : int {
                // echo __METHOD__ . $this->dbgInfo() . ' ';
@@ -210,10 +303,6 @@
                        $rhsTaintedness = $this->mergeAddTaint( 
$rhsTaintedness, $lhsTaintedness );
                }
 
-               /* if ( !(SecurityCheckPlugin::PRESERVE_TAINT & 
$rhsTaintedness) && (SecurityCheckPlugin::PRESERVE_TAINT & $lhsTaintedness) ) {
-                       $this->debug( __METHOD__, "Preserve on LHS but not RHS 
in assignment" );
-               } */
-
                // If we're assigning to a variable we know will be output later
                // raise an issue now.
                if ( !$this->isSafeAssignment( $lhsTaintedness, $rhsTaintedness 
) ) {
@@ -226,7 +315,9 @@
                        );
                }
                foreach ( $variableObjs as $variableObj ) {
-                       // echo $this->dbgInfo() . " " . $variableObj . " now 
merging in taintedness " . $rhsTaintedness . " (previously $lhsTaintedness)\n";
+                       // echo $this->dbgInfo() . " " . $variableObj .
+                       // " now merging in taintedness " . $rhsTaintedness
+                       // . " (previously $lhsTaintedness)\n";
                        $this->setTaintedness( $variableObj, $rhsTaintedness, 
$override );
                        try {
                                if ( !is_object( $node->children['expr'] ) ) {
@@ -234,7 +325,8 @@
                                }
                                $rhsObjs = $this->getPhanObjsForNode( 
$node->children['expr'] );
                        } catch ( Exception $e ) {
-                               $this->debug( __METHOD__, "Cannot get phan 
object for RHS of assign " . get_class( $e ) . $e->getMessage() );
+                               $this->debug( __METHOD__, "Cannot get phan 
object for RHS of assign "
+                                       . get_class( $e ) . $e->getMessage() );
                                continue;
                        }
                        foreach ( $rhsObjs as $rhsObj ) {
@@ -244,6 +336,10 @@
                return $rhsTaintedness;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitBinaryOp( Node $node ) : int {
                $safeBinOps =
                        // Unsure about BITWISE ops, since
@@ -278,14 +374,28 @@
                return $res;
        }
 
+       /**
+        * @todo We need more fine grained handling of arrays.
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitDim( Node $node ) : int {
                return $this->getTaintednessNode( $node->children['expr'] );
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitPrint( Node $node ) : int {
                return $this->visitEcho( $node );
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitIncludeOrEval( Node $node ) : int {
                // FIXME this should be handled differently,
                // since any taint is bad for this case unlike echo
@@ -294,6 +404,12 @@
 
        /**
         * Also handles print, eval() and include() (for now).
+        *
+        * We assume a web based system, where outputting HTML via echo
+        * is bad. This will have false positives in a CLI environment.
+        *
+        * @param Node $node
+        * @return int Taint
         */
        public function visitEcho( Node $node ) : int {
                $taintedness = $this->getTaintedness( $node->children['expr'] );
@@ -308,7 +424,10 @@
                                "Echoing tainted expression ($taintedness)"
                                        . $this->getOriginalTaintLine( 
$node->children['expr'] )
                        );
-               } elseif ( is_object( $node->children['expr'] ) || $taintedness 
& SecurityCheckPlugin::PRESERVE_TAINT ) {
+               } elseif (
+                       is_object( $node->children['expr'] ) ||
+                       $taintedness & SecurityCheckPlugin::PRESERVE_TAINT
+               ) {
                        $phanObjs = $this->getPhanObjsForNode( 
$node->children['expr'] );
                        foreach ( $phanObjs as $phanObj ) {
                                $this->debug( __METHOD__, "Setting $phanObj 
exec due to echo" );
@@ -329,10 +448,18 @@
                return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitStaticCall( Node $node ) : int {
                return $this->visitMethodCall( $node );
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitNew( Node $node ) : int {
                if ( $node->children['class']->kind === \ast\AST_NAME ) {
                        return $this->visitMethodCall( $node );
@@ -343,7 +470,17 @@
        }
 
        /**
-        * This handles MethodCall and StaticCall
+        * Somebody calls a method or function
+        *
+        * This has to figure out:
+        *  Is the return value of the call tainted
+        *  Are any of the arguments tainted
+        *  Does the function do anything scary with its arguments
+        * It also has to maintain quite a bit of book-keeping.
+        *
+        * This also handles (function) call, static call, and new operator
+        * @param Node $node
+        * @return int Taint
         */
        public function visitMethodCall( Node $node ) : int {
                $oldMem = memory_get_peak_usage();
@@ -360,7 +497,10 @@
                try {
                        if ( $node->kind === \ast\AST_NEW ) {
                                $clazzName = 
$node->children['class']->children['name'];
-                               $fqsen = 
FullyQualifiedMethodName::fromStringInContext( $clazzName . '::__construct', 
$this->context );
+                               $fqsen = 
FullyQualifiedMethodName::fromStringInContext(
+                                       $clazzName . '::__construct',
+                                       $this->context
+                               );
                                if ( !$this->code_base->hasMethodWithFQSEN( 
$fqsen ) ) {
                                        echo __METHOD__ . "FIXME no constructor 
or parent class";
                                        throw new exception( "Cannot find 
__construct" );
@@ -378,12 +518,14 @@
                        $funcName = $func->getFQSEN();
                        $taint = $this->getTaintOfFunction( $func );
                } catch ( IssueException $e ) {
-                       $this->debug( __METHOD__, "FIXME complicated case not 
handled. Maybe func not defined." . $e->getIssueInstance() );
+                       $this->debug( __METHOD__, "FIXME complicated case not 
handled. "
+                               . "Maybe func not defined." . 
$e->getIssueInstance() );
                        $func = null;
                        $funcName = '[UNKNOWN FUNC]';
                        $taint = [ 'overall' => 
SecurityCheckPlugin::UNKNOWN_TAINT ];
                } catch ( Exception $e ) {
-                       $this->debug( __METHOD__, "FIXME complicated case not 
handled. Maybe func not defined. " . get_class( $e ) . $e->getMessage() );
+                       $this->debug( __METHOD__, "FIXME complicated case not 
handled."
+                               . " Maybe func not defined. " . get_class( $e ) 
. $e->getMessage() );
                        $func = null;
                        $funcName = '[UNKNOWN FUNC]';
                        $taint = [ 'overall' => 
SecurityCheckPlugin::UNKNOWN_TAINT ];
@@ -404,7 +546,8 @@
                        if ( isset( $taint[$i] ) ) {
                                $effectiveArgTaintedness = $curArgTaintedness &
                                        ( $taint[$i] | $this->execToYesTaint( 
$taint[$i] ) );
-                               # $this->debug( __METHOD__, "effective 
$effectiveArgTaintedness via arg $i $funcName" );
+                               # $this->debug( __METHOD__, "effective 
$effectiveArgTaintedness"
+                                       # . " via arg $i $funcName" );
                        } elseif ( ( $taint['overall'] &
                                ( SecurityCheckPlugin::PRESERVE_TAINT | 
SecurityCheckPlugin::UNKNOWN_TAINT )
                        ) ) {
@@ -414,14 +557,16 @@
                                // pass the taint through.
                                // FIXME, could maybe check if type is safe 
like int.
                                $effectiveArgTaintedness = $curArgTaintedness;
-                               # $this->debug( __METHOD__, "effective 
$effectiveArgTaintedness via preserve or unkown $funcName" );
+                               # $this->debug( __METHOD__, "effective 
$effectiveArgTaintedness"
+                                       # . " via preserve or unkown $funcName" 
);
                        } else {
                                // This parameter has no taint info.
                                // And overall this function doesn't depend on 
param
                                // for taint and isn't unknown.
                                // So we consider this argument untainted.
                                $effectiveArgTaintedness = 
SecurityCheckPlugin::NO_TAINT;
-                               # $this->debug( __METHOD__, "effective 
$effectiveArgTaintedness via no taint info $funcName" );
+                               # $this->debug( __METHOD__, "effective 
$effectiveArgTaintedness"
+                                       # . " via no taint info $funcName" );
                        }
 
                        // -------Start complex reference parameter bit--------/
@@ -458,7 +603,8 @@
                                        $pobjLinks = $pobj->taintedMethodLinks 
?? new Set;
                                        $pobj->taintedMethodLinks = 
$methodLinks->union( $pobjLinks );
                                        $methodVar->taintedMethodLinks =& 
$pobj->taintedMethodLinks;
-                                       $combinedOrig = ( 
$pobj->taintedOriginalError ?? '' ) . ( $methodVar->taintedOriginalError ?? '' 
);
+                                       $combinedOrig = ( 
$pobj->taintedOriginalError ?? '' )
+                                               . ( 
$methodVar->taintedOriginalError ?? '' );
                                        if ( strlen( $combinedOrig ) > 255 ) {
                                                $combinedOrig = substr( 
$combinedOrig, 0, 250 ) . '...';
                                        }
@@ -475,7 +621,8 @@
                        // someFunc( $execArg ) for pass by reference where
                        // the parameter is later executed outside the func.
                        if ( $func && $this->isYesTaint( $curArgTaintedness ) ) 
{
-                               # $this->debug( __METHOD__, "cur arg $i is YES 
taint ($curArgTaintedness). Marking dependent $funcName" );
+                               # $this->debug( __METHOD__, "cur arg $i is YES 
taint " .
+                               # "($curArgTaintedness). Marking dependent 
$funcName" );
                                // Mark all dependent vars as tainted.
                                $this->markAllDependentVarsYes( $func, $i );
                        }
@@ -497,7 +644,9 @@
                        $taintedArg = $argument->children['name'] ?? '[arg #' . 
( $i + 1 ) . ']';
                        // We use curArgTaintedness here, as we aren't checking 
what taint
                        // gets passed to return value, but which taint is 
EXECed.
-                       // $this->debug( __METHOD__, "Checking safe assing 
$funcName arg=$i paramTaint= " .( $taint[$i] ?? "MISSING" ). " vs argTaint= 
$curArgTaintedness"  );
+                       // $this->debug( __METHOD__, "Checking safe assing 
$funcName" .
+                               // " arg=$i paramTaint= " . ( $taint[$i] ?? 
"MISSING" ) .
+                               // " vs argTaint= $curArgTaintedness"  );
                        if ( !$this->isSafeAssignment( $taint[$i] ?? 0, 
$curArgTaintedness ) ) {
                                $containingMethod = $this->getCurrentMethod();
                                $this->plugin->emitIssue(
@@ -549,10 +698,24 @@
                        | ( $overallArgTaint & ~SecurityCheckPlugin::EXEC_TAINT 
);
        }
 
+       /**
+        * A function call
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitCall( Node $node ) : int {
                return $this->visitMethodCall( $node );
        }
 
+       /**
+        * A variable (e.g. $foo)
+        *
+        * This always considers superglobals as tainted
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitVar( Node $node ) : int {
                try {
                        $varName = $this->getCtxN( $node )->getVariableName();
@@ -579,6 +742,12 @@
                return $this->getTaintednessPhanObj( $variableObj );
        }
 
+       /**
+        * A global decleration. Assume most globals are untainted.
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitGlobal( Node $node ) : int {
                assert( isset( $node->children['var'] ) && 
$node->children['var']->kind === \ast\AST_VAR );
                $varName = $node->children['var']->children['name'];
@@ -605,6 +774,16 @@
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * Set the taint of the function based on what's returned
+        *
+        * This attempts to match the return value up to the argument
+        * to figure out which argument might taint the function. This won't
+        * work in complex cases though.
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitReturn( Node $node ) : int {
                if ( !$this->context->isInFunctionLikeScope() ) {
                        $this->debug( __METHOD__, "return outside func?" );
@@ -646,6 +825,8 @@
 
        /**
         * @suppress PhanTypeMismatchForeach
+        * @param Node $node
+        * @return int Taint
         */
        public function visitArray( Node $node ) : int {
                $curTaint = SecurityCheckPlugin::NO_TAINT;
@@ -656,6 +837,11 @@
                return $curTaint;
        }
 
+       /**
+        * A => B
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitArrayElem( Node $node ) : int {
                return $this->mergeAddTaint(
                        $this->getTaintedness( $node->children['value'] ),
@@ -663,26 +849,49 @@
                );
        }
 
+       /**
+        * A foreach() loop
+        *
+        * The variable from the loop condition has its taintedness
+        * transferred in PreTaintednessVisitor
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitForeach( Node $node ) : int {
                // This is handled by PreTaintednessVisitor.
                return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitClassConst( Node $node ) : int {
                return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitConst( Node $node ) : int {
                // We are going to assume nobody is doing stupid stuff like
                // define( "foo", $_GET['bar'] );
                return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * The :: operator (for props)
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitStaticProp( Node $node ) : int {
                try {
                        $props = $this->getPhanObjsForNode( $node );
                } catch ( Exception $e ) {
-                       $this->debug( __METHOD__, "Cannot understand static 
class prop. " . get_class( $e ) . " - {$e->getMessage()}" );
+                       $this->debug( __METHOD__, "Cannot understand static 
class prop. "
+                               . get_class( $e ) . " - {$e->getMessage()}"
+                       );
                        // Debug::printNode( $node );
                        return SecurityCheckPlugin::UNKNOWN_TAINT;
                }
@@ -698,11 +907,17 @@
                return $taint;
        }
 
+       /**
+        * The -> operator (when not a method call)
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitProp( Node $node ) : int {
                try {
                        $props = $this->getPhanObjsForNode( $node );
                } catch ( Exception $e ) {
-                       // $this->debug( __METHOD__, "Cannot understand class 
prop. " . get_class($e) . " - {$e->getMessage()}" );
+                       // $this->debug( __METHOD__, "Cannot understand class 
prop. "
+                       // . get_class($e) . " - {$e->getMessage()}" );
                        // Debug::printNode( $node );
                        return SecurityCheckPlugin::UNKNOWN_TAINT;
                }
@@ -726,7 +941,10 @@
                                is_string( 
$node->children['expr']->children['name'] ) &&
                                is_string( $node->children['prop'] )
                        ) {
-                               $this->debug( __METHOD__, "Could not find 
Property \$" . $node->children['expr']->children['name'] . "->" . 
$node->children['prop'] . "" );
+                               $this->debug( __METHOD__, "Could not find 
Property \$" .
+                                       
$node->children['expr']->children['name'] . "->" .
+                                       $node->children['prop']
+                               );
                        } else {
                                $this->debug( __METHOD__, "Unexpected number of 
phan objs " . count( $props ) . "" );
                                Debug::printNode( $node );
@@ -741,20 +959,32 @@
        }
 
        /**
-        * When a prop is declared
+        * When a class property is declared
+        * @param Node $node
+        * @return int Taint
         */
        public function visitPropElem( Node $node ) : int {
                assert( $this->context->isInClassScope() );
                $clazz = $this->context->getClassInScope( $this->code_base );
 
                assert( $clazz->hasPropertyWithName( $this->code_base, 
$node->children['name'] ) );
-               $prop = $clazz->getPropertyByNameInContext( $this->code_base, 
$node->children['name'], $this->context );
+               $prop = $clazz->getPropertyByNameInContext(
+                       $this->code_base,
+                       $node->children['name'],
+                       $this->context
+               );
                // FIXME should this be NO?
-               // $this->debug( __METHOD__, "Setting taint preserve if not set 
yet for \$" . $node->children['name'] . "" );
+               // $this->debug( __METHOD__, "Setting taint preserve if not set"
+               // . " yet for \$" . $node->children['name'] . "" );
                $this->setTaintedness( $prop, SecurityCheckPlugin::NO_TAINT, 
false );
                return SecurityCheckPlugin::INAPLICABLE_TAINT;
        }
 
+       /**
+        * Ternary operator.
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitConditional( Node $node ) : int {
                if ( $node->children['true'] === null ) {
                        // $foo ?: $bar;
@@ -766,6 +996,10 @@
                return $this->mergeAddTaint( $t, $f );
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitName( Node $node ) : int {
                // FIXME I'm a little unclear on what a name is in php.
                // I think this means literal true, false, null
@@ -776,10 +1010,21 @@
                return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * @todo Is this right? The child condition should
+        *  be visited when going in post order analysis anyways,
+        *  and the taint of an If statement isn't really its condition.
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitIfElem( Node $node ) : int {
                return $this->getTaintedness( $node->children['cond'] );
        }
 
+       /**
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitUnaryOp( Node $node ) : int {
                // ~ and @ are the only two unary ops
                // that can preserve taint (others cast bool or int)
@@ -790,6 +1035,10 @@
                return $this->getTaintedness( $node->children['expr'] );
        }
 
+       /**
+        * @param Node $node
+        * @return int The taint
+        */
        public function visitCast( Node $node ) : int {
                // Casting between an array and object maintains
                // taint. Casting an object to a string calls __toString().
@@ -805,6 +1054,10 @@
        }
 
        /**
+        * The taint is the taint of all the child elements
+        *
+        * @param Node $node
+        * @return int the taint
         * @suppress PhanTypeMismatchForeach
         */
        public function visitEncapsList( Node $node ) : int {
@@ -815,14 +1068,32 @@
                return $taint;
        }
 
+       /**
+        * Visit a node that is always safe
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitIsset( Node $node ) : int {
                return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * Visit a node that is always safe
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitMagicConst( Node $node ) : int {
                return SecurityCheckPlugin::NO_TAINT;
        }
 
+       /**
+        * Visit a node that is always safe
+        *
+        * @param Node $node
+        * @return int Taint
+        */
        public function visitInstanceOf( Node $node ) : int {
                return SecurityCheckPlugin::NO_TAINT;
        }

-- 
To view, visit https://gerrit.wikimedia.org/r/393537
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic802e332ab0fbabc3434b308a41353eaafbab69b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/tools/phan/SecurityCheckPlugin
Gerrit-Branch: master
Gerrit-Owner: Brian Wolff <[email protected]>
Gerrit-Reviewer: Brian Wolff <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to