Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1432830
CompositionAnalyzer.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
CompositionAnalyzer.php
View Options
<?php
declare
(
strict_types
=
1
);
namespace
Phan\Analysis
;
use
Phan\CodeBase
;
use
Phan\Exception\IssueException
;
use
Phan\Issue
;
use
Phan\Language\Element\Clazz
;
use
Phan\Language\Element\Flags
;
use
Phan\Language\UnionType
;
/**
* This analyzer checks if the signatures of inherited properties match
* and for type mismatches for php 7.4 typed properties.
*/
class
CompositionAnalyzer
{
/**
* Check to see if the signatures of inherited properties match
*/
public
static
function
analyzeComposition
(
CodeBase
$code_base
,
Clazz
$class
):
void
{
// 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 anything.
if
(!
$inherited_class_list
)
{
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.
// (This must be done after hydration, because some properties are loaded from traits)
foreach
(
$class
->
getPropertyMap
(
$code_base
)
as
$property
)
{
if
(
$property
->
getPhanFlagsHasState
(
Flags
::
IS_ENUM_PROPERTY
))
{
continue
;
}
try
{
$property_union_type
=
$property
->
getDefaultType
()
??
UnionType
::
empty
();
}
catch
(
IssueException
$_
)
{
$property_union_type
=
UnionType
::
empty
();
}
// Check for that property on each inherited
// class/trait/interface
foreach
(
$inherited_class_list
as
$inherited_class
)
{
$inherited_class
->
hydrate
(
$code_base
);
// 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
()];
if
(
$inherited_property
->
isDynamicOrFromPHPDoc
())
{
continue
;
}
if
(
$inherited_property
->
getRealDefiningFQSEN
()
===
$property
->
getRealDefiningFQSEN
())
{
continue
;
}
// Figure out if this property type can cast to the
// inherited definition's type.
// Use the phpdoc comment or real type declaration instead of the inferred
// types from the default to perform this check.
try
{
$inherited_property_union_type
=
$inherited_property
->
getDefaultType
()
??
UnionType
::
empty
();
}
catch
(
IssueException
$_
)
{
$inherited_property_union_type
=
UnionType
::
empty
();
}
// Don't complain about incompatible types if the base property is private, #4426
if
(!
$property
->
isDynamicOrFromPHPDoc
()
&&
!
$inherited_property
->
isPrivate
())
{
$real_property_type
=
$property
->
getRealUnionType
()->
asNormalizedTypes
();
$real_inherited_property_type
=
$inherited_property
->
getRealUnionType
()->
asNormalizedTypes
();
if
(!
$real_property_type
->
isEqualTo
(
$real_inherited_property_type
))
{
Issue
::
maybeEmit
(
$code_base
,
$property
->
getContext
(),
Issue
::
IncompatibleRealPropertyType
,
$property
->
getFileRef
()->
getLineNumberStart
(),
$property
->
getFQSEN
(),
$real_property_type
,
$inherited_property
->
getFQSEN
(),
$real_inherited_property_type
,
$inherited_property
->
getFileRef
()->
getFile
(),
$inherited_property
->
getFileRef
()->
getLineNumberStart
()
);
}
}
if
(
$property
->
getFQSEN
()
===
$property
->
getRealDefiningFQSEN
())
{
// No need to warn about incompatible composition of trait with another ancestor if the property's default was overridden
continue
;
}
// TODO: Why expand?
$can_cast
=
$property_union_type
->
canCastToUnionType
(
$inherited_property_union_type
->
asExpandedTypes
(
$code_base
),
$code_base
);
if
(
$can_cast
)
{
continue
;
}
// Don't emit an issue if the property suppresses the issue
// NOTE: The current context is the class, not either of the properties.
if
(
$property
->
checkHasSuppressIssueAndIncrementCount
(
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
(),
$property_union_type
,
$inherited_property_union_type
,
$class
->
getFileRef
()->
getFile
(),
$class
->
getFileRef
()->
getLineNumberStart
()
);
}
}
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 22:22 (1 d, 2 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
0f/15/f8809a3994e91132ccfac349101a
Default Alt Text
CompositionAnalyzer.php (6 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment