Phan\Analysis\CompositionAnalyzer::analyzeComposition PHP Method

analyzeComposition() public static method

Check to see if signatures match
public static analyzeComposition ( CodeBase $code_base, Clazz $class ) : void
$code_base Phan\CodeBase
$class Phan\Language\Element\Clazz
return void
    public static function analyzeComposition(CodeBase $code_base, Clazz $class)
    {
        // Get the Class's FQSEN
        $fqsen = $class->getFQSEN();
        // Get the list of all inherited classes.
        $inherited_class_list = $class->getAncestorClassList($code_base);
        // No chance of failed composition if we don't inherit from
        // lots of stuff.
        if (count($inherited_class_list) < 2) {
            return;
        }
        // Since we're not necessarily getting this list of classes
        // via getClass, we need to ensure that hydration has occurred.
        $class->hydrate($code_base);
        // For each property, find out every inherited class that defines it
        // and check to see if the types line up.
        foreach ($class->getPropertyList($code_base) as $property) {
            try {
                $property_union_type = $property->getUnionType();
            } catch (IssueException $exception) {
                $property_union_type = new UnionType();
            }
            // Check for that property on each inherited
            // class/trait/interface
            foreach ($inherited_class_list as $inherited_class) {
                // Skip any classes/traits/interfaces not defining that
                // property
                if (!$inherited_class->hasPropertyWithName($code_base, $property->getName())) {
                    continue;
                }
                // We don't call `getProperty` because that will create
                // them in some circumstances.
                $inherited_property_map = $inherited_class->getPropertyMap($code_base);
                if (!isset($inherited_property_map[$property->getName()])) {
                    continue;
                }
                // Get the inherited property
                $inherited_property = $inherited_property_map[$property->getName()];
                // Figure out if this property type can cast to the
                // inherited definition's type.
                $can_cast = $property_union_type->canCastToExpandedUnionType($inherited_property->getUnionType(), $code_base);
                if ($can_cast) {
                    continue;
                }
                // Don't emit an issue if the property suppresses the issue
                if ($property->hasSuppressIssue(Issue::IncompatibleCompositionProp)) {
                    continue;
                }
                Issue::maybeEmit($code_base, $property->getContext(), Issue::IncompatibleCompositionProp, $property->getFileRef()->getLineNumberStart(), (string) $class->getFQSEN(), (string) $inherited_class->getFQSEN(), $property->getName(), (string) $class->getFQSEN(), $class->getFileRef()->getFile(), $class->getFileRef()->getLineNumberStart());
            }
        }
        // TODO: This has too much overlap with PhanParamSignatureMismatch
        //       and we should figure out how to merge it.
        /*
        $method_map =
            $code_base->getMethodMapByFullyQualifiedClassName($fqsen);
        
        // For each method, find out every inherited class that defines it
        // and check to see if the types line up.
        foreach ($method_map as $i => $method) {
        
            $method_union_type = $method->getUnionType();
        
            // We don't need to analyze constructors for signature
            // compatibility
            if ($method->getName() == '__construct') {
                continue;
            }
        
            // Get the method parameter list
        
            // Check for that method on each inherited
            // class/trait/interface
            foreach ($inherited_class_list as $inherited_class) {
        
                // Skip anything that doesn't define this method
                if (!$inherited_class->hasMethodWithName($code_base, $method->getName())) {
                    continue;
                }
        
                $inherited_method =
                    $inherited_class->getMethodByName($code_base, $method->getName());
        
                if ($method == $inherited_method) {
                    continue;
                }
        
                // Figure out if this method return type can cast to the
                // inherited definition's return type.
                $is_compatible =
                    $method_union_type->canCastToExpandedUnionType(
                        $inherited_method->getUnionType(),
                        $code_base
                    );
        
                $inherited_method_parameter_map =
                    $inherited_method->getParameterList();
        
                // Figure out if all of the parameter types line up
                foreach ($method->getParameterList() as $i => $parameter) {
                    $is_compatible = (
                        $is_compatible
                        && isset($inherited_method_parameter_map[$i])
                        && $parameter->getUnionType()->canCastToExpandedUnionType(
                            ($inherited_method_parameter_map[$i])->getUnionType(),
                            $code_base
                        )
                    );
                }
        
                if ($is_compatible) {
                    continue;
                }
        
                // Don't emit an issue if the method suppresses the issue
                if ($method->hasSuppressIssue(Issue::IncompatibleCompositionMethod)) {
                    continue;
                }
        
                Issue::maybeEmit(
                    $code_base,
                    $method->getContext(),
                    Issue::IncompatibleCompositionMethod,
                    $method->getFileRef()->getLineNumberStart(),
                    (string)$method,
                    (string)$inherited_method,
                    $inherited_method->getFileRef()->getFile(),
                    $inherited_method->getFileRef()->getLineNumberStart()
                );
            }
        }
        */
    }

Usage Example

Example #1
0
File: Clazz.php Project: etsy/phan
 /**
  * This method should be called after hydration
  *
  * @return void
  */
 public final function analyze(CodeBase $code_base)
 {
     if ($this->isInternal()) {
         return;
     }
     // Make sure the parent classes exist
     ParentClassExistsAnalyzer::analyzeParentClassExists($code_base, $this);
     DuplicateClassAnalyzer::analyzeDuplicateClass($code_base, $this);
     ParentConstructorCalledAnalyzer::analyzeParentConstructorCalled($code_base, $this);
     PropertyTypesAnalyzer::analyzePropertyTypes($code_base, $this);
     // Analyze this class to make sure that we don't have conflicting
     // types between similar inherited methods.
     CompositionAnalyzer::analyzeComposition($code_base, $this);
     // Let any configured plugins analyze the class
     ConfigPluginSet::instance()->analyzeClass($code_base, $this);
 }
All Usage Examples Of Phan\Analysis\CompositionAnalyzer::analyzeComposition
CompositionAnalyzer