/** * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return \PDepend\Source\AST\AbstractASTCallable */ protected function parseCallableDeclarationAddition($callable) { $this->consumeComments(); if (Tokens::T_COLON != $this->tokenizer->peek()) { return $callable; } $this->consumeToken(Tokens::T_COLON); $type = $this->parseReturnTypeHint(); $callable->addChild($type); return $callable; }
/** * This method will return the class where the parent method was declared. * The returned value will be <b>null</b> if the parent is a function. * * @return \PDepend\Source\AST\AbstractASTClassOrInterface * @since 0.9.5 */ public function getDeclaringClass() { // TODO: Review this for refactoring, maybe create a empty getParent()? if ($this->declaringFunction instanceof ASTMethod) { return $this->declaringFunction->getParent(); } return null; }
/** * Visits methods, functions or closures and calculated their complexity. * * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return void * @since 0.9.8 */ public function calculateComplexity(AbstractASTCallable $callable) { $data = array(self::M_CYCLOMATIC_COMPLEXITY_1 => 1, self::M_CYCLOMATIC_COMPLEXITY_2 => 1); foreach ($callable->getChildren() as $child) { $data = $child->accept($this, $data); } $this->metrics[$callable->getId()] = $data; }
/** * Extracts documented <b>throws</b> and <b>return</b> types and sets them * to the given <b>$callable</b> instance. * * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return void */ private function prepareCallable(AbstractASTCallable $callable) { // Skip, if ignore annotations is set if ($this->ignoreAnnotations === true) { return; } // Get all @throws Types $throws = $this->parseThrowsAnnotations($callable->getDocComment()); foreach ($throws as $qualifiedName) { $callable->addExceptionClassReference($this->builder->buildAstClassOrInterfaceReference($qualifiedName)); } // Get return annotation $qualifiedName = $this->parseReturnAnnotation($callable->getDocComment()); if ($qualifiedName !== null) { $callable->setReturnClassReference($this->builder->buildAstClassOrInterfaceReference($qualifiedName)); } }
/** * Visits the given callable instance. * * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return void */ private function visitCallable(AbstractASTCallable $callable) { $this->metrics[$callable->getId()] = array(self::M_CRAP_INDEX => $this->calculateCrapIndex($callable), self::M_COVERAGE => $this->calculateCoverage($callable)); }
/** * The magic sleep method will be called by the PHP engine when this class * gets serialized. It returns an array with those properties that should be * cached for method instances. * * @return array(string) * @since 0.10.0 */ public function __sleep() { return array_merge(array('modifiers'), parent::__sleep()); }
/** * @see http://www.scribd.com/doc/99533/Halstead-s-Operators-and-Operands-in-C-C-JAVA-by-Indranil-Nandy * * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return void */ public function calculateHalsteadBasis(AbstractASTCallable $callable) { $operators = array(); $operands = array(); $skipUntil = null; $tokens = $callable->getTokens(); foreach ($tokens as $i => $token) { /* * Some operations should be ignored, e.g. function declarations. * When we encounter a new function, we'll skip all tokens until we * find the closing token. */ if ($skipUntil !== null) { if ($token->type === $skipUntil) { $skipUntil = null; } continue; } switch ($token->type) { // A pair of parenthesis is considered a single operator. case Tokens::T_PARENTHESIS_CLOSE: case Tokens::T_CURLY_BRACE_CLOSE: case Tokens::T_SQUARED_BRACKET_CLOSE: case Tokens::T_ANGLE_BRACKET_CLOSE: break; // A label is considered an operator if it is used as the target // of a GOTO statement. // A label is considered an operator if it is used as the target // of a GOTO statement. case Tokens::T_GOTO: $operators[] = $token->image; // Ignore next token as operand but count as operator instead. $skipUntil = $tokens[$i + 1]->type; $operators[] = $tokens[$i + 1]->image; break; /* * The following control structures case ...: for (...) if (...) * switch (...) while(...) and try-catch (...) are treated in a * special way. The colon and the parentheses are considered to * be a part of the constructs. The case and the colon or the * “for (...)”, “if (...)”, “switch (...)”, “while(...)”, * “try-catch( )” are counted together as one operator. */ // case Tokens::T_SWITCH: // not followed by () // case Tokens::T_TRY: // not followed by () // case Tokens::T_DO: // always comes with while, which accounts for () already /* * The following control structures case ...: for (...) if (...) * switch (...) while(...) and try-catch (...) are treated in a * special way. The colon and the parentheses are considered to * be a part of the constructs. The case and the colon or the * “for (...)”, “if (...)”, “switch (...)”, “while(...)”, * “try-catch( )” are counted together as one operator. */ // case Tokens::T_SWITCH: // not followed by () // case Tokens::T_TRY: // not followed by () // case Tokens::T_DO: // always comes with while, which accounts for () already case Tokens::T_IF: case Tokens::T_FOR: case Tokens::T_FOREACH: case Tokens::T_WHILE: case Tokens::T_CATCH: $operators[] = $token->image; /* * These are always followed by parenthesis, which would add * another operator (only opening parenthesis counts) * so we'll have to skip that one. */ $skipUntil = Tokens::T_PARENTHESIS_OPEN; break; /* * The ternary operator ‘?’ followed by ‘:’ is considered a * single operator as it is equivalent to “if-else” construct. */ /* * The ternary operator ‘?’ followed by ‘:’ is considered a * single operator as it is equivalent to “if-else” construct. */ case Tokens::T_COLON: /* * Colon is used after keyword, where it counts as part of * that operator, or in ternary operator, where it also * counts as 1. */ break; // The comments are considered neither an operator nor an operand. // The comments are considered neither an operator nor an operand. case Tokens::T_DOC_COMMENT: case Tokens::T_COMMENT: break; /* * `new` is considered same as the function call, mainly because * it's equivalent to the function call. */ /* * `new` is considered same as the function call, mainly because * it's equivalent to the function call. */ case Tokens::T_NEW: break; /* * Like T_IF & co, array(..) needs 3 tokens ("array", "(" and * ")") for what's essentially just 1 operator. */ /* * Like T_IF & co, array(..) needs 3 tokens ("array", "(" and * ")") for what's essentially just 1 operator. */ case Tokens::T_ARRAY: break; /* * Class::method or $object->method both only count as 1 * identifier, even though they consist of 3 tokens. */ /* * Class::method or $object->method both only count as 1 * identifier, even though they consist of 3 tokens. */ case Tokens::T_OBJECT_OPERATOR: case Tokens::T_DOUBLE_COLON: // Glue ->/:: and before & after parts together. $image = array_pop($operands) . $token->image . $tokens[$i + 1]->image; $operands[] = $image; // Skip next part (would be seen as operand) $skipUntil = $tokens[$i + 1]->type; break; // Ignore HEREDOC delimiters. // Ignore HEREDOC delimiters. case Tokens::T_START_HEREDOC: case Tokens::T_END_HEREDOC: break; // Ignore PHP open & close tags and non-PHP content. // Ignore PHP open & close tags and non-PHP content. case Tokens::T_OPEN_TAG: case Tokens::T_CLOSE_TAG: case Tokens::T_NO_PHP: break; /* * The function name is considered a single operator when it * appears as calling a function, but when it appears in * declarations or in function definitions it is not counted as * operator. * Default parameter assignments are not counted. */ /* * The function name is considered a single operator when it * appears as calling a function, but when it appears in * declarations or in function definitions it is not counted as * operator. * Default parameter assignments are not counted. */ case Tokens::T_FUNCTION: // Because `)` could appear in default argument assignment // (`$var = array()`), we need to skip until `{`, but that // one should be included in operators. $skipUntil = Tokens::T_CURLY_BRACE_OPEN; $operators[] = '{'; break; /* * When variables or constants appear in declaration they are * not considered as operands, they are considered operands only * when they appear with operators in expressions. */ /* * When variables or constants appear in declaration they are * not considered as operands, they are considered operands only * when they appear with operators in expressions. */ case Tokens::T_VAR: case Tokens::T_CONST: $skipUntil = Tokens::T_SEMICOLON; break; case Tokens::T_STRING: // `define` is T_STRING, just like any other identifier. if ($token->image === 'define') { // Undo all of "define", "(", name, ",", value, ")" $skipUntil = Tokens::T_PARENTHESIS_CLOSE; } else { $operands[] = $token->image; } break; // Operands // Operands case Tokens::T_CONSTANT_ENCAPSED_STRING: case Tokens::T_VARIABLE: case Tokens::T_LNUMBER: case Tokens::T_DNUMBER: case Tokens::T_NUM_STRING: case Tokens::T_NULL: case Tokens::T_TRUE: case Tokens::T_FALSE: case Tokens::T_CLASS_FQN: case Tokens::T_LINE: case Tokens::T_METHOD_C: case Tokens::T_NS_C: case Tokens::T_DIR: case TOKENS::T_ENCAPSED_AND_WHITESPACE: // content of HEREDOC $operands[] = $token->image; break; // Everything else is an operator. // Everything else is an operator. default: $operators[] = $token->image; break; } } $this->metrics[$callable->getId()] = array('n1' => count($operators), 'n2' => count($operands), 'N1' => count(array_unique($operators)), 'N2' => count(array_unique($operands))); }
/** * The magic sleep method will be called by the PHP engine when this class * gets serialized. It returns an array with those properties that should be * cached for all function instances. * * @return array(string) * @since 0.10.0 */ public function __sleep() { return array_merge(array('context', 'namespaceName'), parent::__sleep()); }
/** * This method will calculate the NPath complexity for the given callable * instance. * * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return void * @since 0.9.12 */ protected function calculateComplexity(AbstractASTCallable $callable) { $npath = '1'; foreach ($callable->getChildren() as $child) { $stmt = $child->accept($this, $npath); $npath = MathUtil::mul($npath, $stmt); } $this->metrics[$callable->getId()] = $npath; }
/** * Counts all calls within the given <b>$callable</b> * * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return void */ private function countCalls(AbstractASTCallable $callable) { $invocations = $callable->findChildrenOfType('PDepend\\Source\\AST\\ASTInvocation'); $invoked = array(); foreach ($invocations as $invocation) { $parents = $invocation->getParentsOfType('PDepend\\Source\\AST\\ASTMemberPrimaryPrefix'); $image = ''; foreach ($parents as $parent) { $child = $parent->getChild(0); if ($child !== $invocation) { $image .= $child->getImage() . '.'; } } $image .= $invocation->getImage() . '()'; $invoked[$image] = $image; } $this->calls += count($invoked); }
/** * Calculates the NPath complexity for the given callable instance. * * @param \PDepend\Source\AST\AbstractASTCallable $callable * @return string * @since 0.9.12 */ private function _calculateNPathComplexity(AbstractASTCallable $callable) { $analyzer = $this->_createAnalyzer(); $callable->accept($analyzer); $metrics = $analyzer->getNodeMetrics($callable); return $metrics['npath']; }