use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class OffsetOperationsInspector method isContainerSupportsArrayAccess.
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean isContainerSupportsArrayAccess(@NotNull ArrayAccessExpression expression, @NotNull Set<String> indexTypesSupported) {
// ok JB parses `$var[]= ...` always as array, lets make it working properly and report them later
final PsiElement container = expression.getValue();
if (null == container) {
return false;
}
final Set<String> containerTypes = new HashSet<>();
if (container instanceof PhpTypedElement) {
final PhpType type = OpenapiResolveUtil.resolveType((PhpTypedElement) container, container.getProject());
if (type != null && !type.hasUnknown()) {
type.getTypes().forEach(t -> containerTypes.add(Types.getType(t)));
}
}
/* === cleanup resolved types === */
if (containerTypes.contains(Types.strMixed)) {
// mixed are not analyzable
containerTypes.clear();
return true;
}
if (containerTypes.size() == 2 && containerTypes.contains(Types.strString)) {
final boolean isForeachKeyType = containerTypes.contains(Types.strInteger);
final boolean isCoreApiStringType = containerTypes.contains(Types.strBoolean);
if (isForeachKeyType || isCoreApiStringType) {
containerTypes.clear();
return true;
}
}
if (containerTypes.contains(Types.strCallable)) {
// treat callable as array
containerTypes.remove(Types.strCallable);
containerTypes.add(Types.strArray);
containerTypes.add(Types.strString);
}
// don't process nulls
containerTypes.remove(Types.strNull);
// don't process generalized objects
containerTypes.remove(Types.strObject);
// don't process mysterious empty set type
containerTypes.remove(Types.strEmptySet);
/* === if we could not resolve container, do nothing === */
if (containerTypes.isEmpty()) {
return true;
}
final Project project = container.getProject();
final PhpIndex index = PhpIndex.getInstance(project);
boolean supportsOffsets = false;
for (final String typeToCheck : containerTypes) {
// commonly used case: string and array
if (typeToCheck.equals(Types.strArray) || typeToCheck.equals(Types.strString)) {
supportsOffsets = true;
/* here we state which regular index types we want to promote */
indexTypesSupported.add(Types.strString);
indexTypesSupported.add(Types.strInteger);
continue;
}
// some of possible types are scalars, what's wrong
if (!typeToCheck.isEmpty() && typeToCheck.charAt(0) != '\\') {
supportsOffsets = false;
break;
}
// now we are at point when analyzing classes only
final List<PhpClass> classes = OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(typeToCheck, index);
for (final PhpClass clazz : classes) {
/* custom offsets management, follow annotated types */
for (final String methodName : Arrays.asList("offsetGet", "offsetSet", "__get", "__set")) {
final Method method = OpenapiResolveUtil.resolveMethod(clazz, methodName);
if (method != null) {
/* regular array index types can be applied */
if (methodName.startsWith("__")) {
indexTypesSupported.add(Types.strString);
indexTypesSupported.add(Types.strInteger);
} else /* user-defined index types can be applied */
{
final Parameter[] parameters = method.getParameters();
if (parameters.length > 0) {
final PhpType type = OpenapiResolveUtil.resolveType(parameters[0], project);
if (type != null) {
type.filterUnknown().getTypes().forEach(t -> indexTypesSupported.add(Types.getType(t)));
}
}
}
supportsOffsets = true;
}
}
}
classes.clear();
}
// when might not support offset access, reuse types container to report back why
if (!supportsOffsets) {
indexTypesSupported.clear();
indexTypesSupported.addAll(containerTypes);
}
containerTypes.clear();
return supportsOffsets;
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class AdditionOperationOnArraysInspection method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpBinaryExpression(@NotNull BinaryExpression expression) {
final PsiElement operation = expression.getOperation();
if (OpenapiTypesUtil.is(operation, PhpTokenTypes.opPLUS)) {
/* do not check nested operations */
final boolean isNestedBinary = expression.getParent() instanceof BinaryExpression;
if (!isNestedBinary) {
/* do not report ' ... + []' and '[] + ...' */
final PsiElement right = expression.getRightOperand();
PsiElement left = expression.getLeftOperand();
while (left instanceof BinaryExpression) {
left = ((BinaryExpression) left).getLeftOperand();
}
if (left != null && right != null) {
final boolean addsImplicitArray = left instanceof ArrayCreationExpression || right instanceof ArrayCreationExpression;
if (!addsImplicitArray) {
this.inspectExpression(operation, expression);
}
}
}
}
}
@Override
public void visitPhpSelfAssignmentExpression(@NotNull SelfAssignmentExpression expression) {
final PsiElement operation = expression.getOperation();
if (OpenapiTypesUtil.is(operation, PhpTokenTypes.opPLUS_ASGN)) {
/* do not report '... += []' */
final boolean addsImplicitArray = expression.getValue() instanceof ArrayCreationExpression;
if (!addsImplicitArray) {
this.inspectExpression(operation, expression);
}
}
}
/* inspection itself */
private void inspectExpression(@NotNull PsiElement operation, @NotNull PsiElement expression) {
if (expression instanceof PhpTypedElement) {
final Set<String> types = new HashSet<>();
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) expression, holder.getProject());
if (resolved != null) {
resolved.filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
}
if (types.size() == 1 && types.contains(Types.strArray)) {
holder.registerProblem(operation, message);
}
types.clear();
}
}
};
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class ComparableCoreClassesStrategy method isComparableObject.
private static boolean isComparableObject(@NotNull PsiElement operand, @NotNull PhpIndex index) {
/* extract types of operand, check if classes are/inherited from \DateTime */
final Set<String> operandTypes = new HashSet<>();
if (operand instanceof PhpTypedElement) {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) operand, operand.getProject());
if (resolved != null) {
resolved.filterUnknown().getTypes().forEach(t -> operandTypes.add(Types.getType(t)));
}
}
if (!TypesSemanticsUtil.isNullableObjectInterface(operandTypes)) {
operandTypes.clear();
return false;
}
/* collect classes to check for \DateTime relationship */
final List<PhpClass> operandClasses = new ArrayList<>();
operandTypes.stream().filter(fqn -> fqn.charAt(0) == '\\').forEach(fqn -> operandClasses.addAll(OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(fqn, index)));
operandTypes.clear();
/* inspect classes for being a/child of special once */
for (final PhpClass clazz : operandClasses) {
final HashSet<PhpClass> hierarchy = InterfacesExtractUtil.getCrawlInheritanceTree(clazz, true);
for (final PhpClass oneClass : hierarchy) {
if (comparableObjects.contains(oneClass.getFQN())) {
return true;
}
}
hierarchy.clear();
}
operandClasses.clear();
return false;
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project yii2support by nvlad.
the class ClassUtils method getClassByVariable.
@Nullable
public static PhpClass getClassByVariable(Variable element) {
if (element == null)
return null;
PhpType type = element.getType();
String typeString = type.toString();
String[] split = typeString.split("\\|");
typeString = split[0];
Pattern pattern = Pattern.compile("\\\\[A-Za-z\\\\]+");
Matcher matcher = pattern.matcher(typeString);
if (matcher.find())
typeString = matcher.group();
Collection<PhpClass> anyByFQN = PhpIndex.getInstance(element.getProject()).getAnyByFQN(typeString);
if (anyByFQN.isEmpty())
return null;
else
return anyByFQN.iterator().next();
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project yii2support by nvlad.
the class ClassUtils method getPhpClassByCallChain.
@Nullable
public static PhpClass getPhpClassByCallChain(MethodReference methodRef) {
while (methodRef != null) {
PhpExpression expr = methodRef.getClassReference();
if (expr instanceof ClassReference) {
return (PhpClass) ((ClassReference) expr).resolve();
} else if (expr instanceof MethodReference) {
methodRef = (MethodReference) expr;
} else if (expr instanceof Variable) {
PhpType type = expr.getType();
String strType = type.toString();
int index1 = strType.indexOf('\\');
int index2 = strType.indexOf('.');
if (index2 == -1)
index2 = strType.length() - index1;
if (index1 >= 0 && index2 >= 0 && index2 > index1) {
String className = strType.substring(index1, index2);
return ClassUtils.getClass(PhpIndex.getInstance(methodRef.getProject()), className);
} else {
return null;
}
// type.toString()
} else {
return null;
}
}
return null;
}
Aggregations