/** * @param Project $project */ public function analyze(Project $project) { $logger = $project->getLogger(); foreach ($project->getSplFileInfos() as $splFileInfo) { try { $source = file($splFileInfo->getRealPath()); $code = join('', $source); } catch (\RuntimeException $e) { $project->addReport(new StringReport($e->getMessage())); continue; } try { $logger->info('Parsing ' . $splFileInfo->getRealPath()); $tree = $this->parser->parse($code); $project->addFile(new File($splFileInfo, $source, $tree)); } catch (Error $e) { $project->getLogger()->warning('[' . $this->getName() . '] ' . 'Error while parsing ' . $splFileInfo->getRealPath() . ' : ' . $e->getMessage()); $project->addReport(new FileParserErrorReport($splFileInfo, $e)); } } }
/** * Called when entering a node. * * Return value semantics: * * null: $node stays as-is * * otherwise: $node is set to the return value * * @param Node $node Node * * @return null|Node Node */ public function enterNode(Node $node) { if ($node instanceof Node\Stmt\Catch_) { $this->subNodeTraverser->traverse($node->stmts); $nonComments = $this->nonCommentCounterVisitor->getNonCommentStatements(); if (0 === $nonComments) { $report = new StringReport('Empty catch block found'); $line = $node->getAttribute('startLine') - 1; $report->setSourceFragment(new SourceFragment($this->currentFile, new Lines($line - $this->sourceContext, $line + $this->sourceContext, $line))); $this->project->addReport($report); } } }
/** * @param Project $project */ public function analyze(Project $project) { foreach ($this->graph->getObjects() as $object) { if ($object instanceof ParsedInterface) { foreach ($object->getMethods() as $method) { if ($method->getMethod()->isAbstract()) { $report = new StringReport('Access type for interface method ' . $object->getName() . '::' . $method->getNameAndParamsSignature() . ' must be ommmited in ' . $object->getFile()->getSplFile()->getRealPath() . ':' . $object->getInterface()->getLine()); $report->setSourceFragment(new SourceFragment($object->getFile(), new Lines($method->getMethod()->getAttribute('startLine') - 1 - $this->sourceContext, $method->getMethod()->getAttribute('endLine') - 1 + $this->sourceContext, $method->getMethod()->getAttribute('startLine') - 1))); $project->addReport($report); } } } } }
/** * @param Project $project */ public function analyze(Project $project) { foreach ($this->graph->getObjects() as $object) { if ($object instanceof ParsedInterface) { foreach ($object->getMethods() as $method) { $methodCompare = new MethodSignatureCompare($method); foreach ($this->checkInterfaceMethods($methodCompare, $this->helper->findInterfaceImplements($object)) as $brokenInterfaceAndMethod) { $report = new Report($brokenInterfaceAndMethod, $method); $report->setSourceFragment(new SourceFragment($object->getFile(), new Lines($method->getMethod()->getAttribute('startLine') - 1 - $this->sourceContext, $method->getMethod()->getAttribute('endLine') - 1 + $this->sourceContext, $method->getMethod()->getAttribute('startLine') - 1))); $project->addReport($report); } } } } }
/** * Called when entering a node. * * Return value semantics: * * null: $node stays as-is * * otherwise: $node is set to the return value * * @param Node $node Node * * @return null|Node Node */ public function enterNode(Node $node) { if ($node instanceof New_) { if ($node->class instanceof Variable) { $msg = 'Dynamic class instantiation with variable '; if ($node->class->name instanceof Variable) { $msg .= 'variable $' . $node->class->name->name; } else { $msg .= '$' . $node->class->name; } $report = new StringReport($msg . ' in ' . $this->currentFile->getSplFile()->getFilename() . ':' . $node->class->getLine()); $report->setSourceFragment(new SourceFragment($this->currentFile, new Lines($node->class->getAttribute('startLine') - 1 - $this->sourceContext, $node->class->getAttribute('endLine') - 1 + $this->sourceContext, $node->class->getAttribute('startLine') - 1))); $this->project->addReport($report); } } }
/** * @param Project $project * @return \string[] */ public function analyze(Project $project) { $graph = $this->objectGraph; /** @var ParsedClass[] $classesMissingMethod */ $classesMissingMethods = new Map(function ($key) { if ($key instanceof ParsedClass) { return; } throw new MapException('Only keys of type Class_ are accepted'); }, function ($value) { if (is_array($value)) { return; } throw new MapException('Only values of type array are accepted'); }); # scan all objects (we're actually only interested in interfaces) foreach ($graph->getObjects() as $object) { if ($object instanceof ParsedInterface) { foreach ($object->getMethods() as $method) { # now find all classes and class from interfaces extending this # interface $classesMissingMethod = $this->findSubtypeUntilMethodMatchesRecursive($method, $this->helper->findImplements($object)); # in case we found ones, store them for reporting later # note: we may find other methods in the same class later too foreach ($classesMissingMethod as $classMissingMethod) { $methods = []; if ($classesMissingMethods->exists($classMissingMethod)) { $methods = $classesMissingMethods->get($classMissingMethod); } $methods[] = $method; $classesMissingMethods->set($classMissingMethod, $methods); } } } } /** @var ParsedClass $class */ foreach ($classesMissingMethods->keys() as $class) { $project->addReport(new InterfaceMissingReport($class, $classesMissingMethods->get($class))); } }
/** * @param Project $project */ public function analyze(Project $project) { $this->project = $project; $traverser = new NodeTraverser(); $traverser->addVisitor($this); foreach ($project->getFiles() as $file) { $this->currentFile = $file; $traverser->traverse($file->getTree()); foreach ($this->variables as $variable) { $report = new StringReport('Variable used in constructing raw SQL, is it escaped?'); $line = $variable->getAttribute('startLine') - 1; $report->setSourceFragment(new SourceFragment($file, new Lines($line - $this->sourceContext, $line + $this->sourceContext, $line))); $project->addReport($report); } } }
/** * @param Project $project * @return \string[] */ public function analyze(Project $project) { $graph = $this->objectGraph; /** @var ParsedClass[] $classesMissingMethod */ $classesMissingMethods = new Map(function ($key) { if ($key instanceof ParsedClass) { return; } throw new MapException('Only keys of type Class_ are accepted'); }, function ($value) { if (is_array($value)) { return; } throw new MapException('Only values of type array are accepted'); }); # scan all objects (we're actually only interested in classes) foreach ($graph->getObjects() as $object) { if ($object instanceof ParsedClass) { foreach ($object->getMethods() as $method) { # and see if they've abstract methods if ($method->getMethod()->isAbstract()) { $methodName = $method->getNormalizedName(); # now find all descendant classes and see if they've implemented it $classesMissingMethod = $this->findSubtypeUntilMethodMatchesRecursive($methodName, $this->helper->findExtends($object)); # in case we found ones, store them for reporting later # note: we may find other methods in the same class later too foreach ($classesMissingMethod as $classMissingMethod) { $methods = []; if ($classesMissingMethods->exists($classMissingMethod)) { $methods = $classesMissingMethods->get($classMissingMethod); } $methods[] = $method; $classesMissingMethods->set($classMissingMethod, $methods); } } } } } /** @var ParsedClass $class */ foreach ($classesMissingMethods->keys() as $class) { $project->addReport(new AbstractMissingReport($class, $classesMissingMethods->get($class))); } }