use of com.jetbrains.php.lang.psi.elements.PhpTypedElement 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.elements.PhpTypedElement 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.elements.PhpTypedElement in project phpinspectionsea by kalessil.
the class TypeUnsafeArraySearchInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
final String functionName = reference.getName();
if (functionName != null && targetFunctions.contains(functionName)) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 2) {
/* false-positives: array of string literals */
if (arguments[1] instanceof ArrayCreationExpression) {
final PsiElement[] elements = arguments[1].getChildren();
if (elements.length > 0) {
final long validElementsCount = Arrays.stream(elements).filter(element -> OpenapiTypesUtil.is(element, PhpElementTypes.ARRAY_VALUE)).map(PsiElement::getFirstChild).filter(element -> element instanceof StringLiteralExpression).map(literal -> ((StringLiteralExpression) literal).getContents().trim()).filter(content -> !content.isEmpty() && !content.matches("^\\d+$")).count();
if (validElementsCount == elements.length) {
return;
}
}
}
/* false-positives: array and item types are complimentary */
if (arguments[0] instanceof PhpTypedElement && arguments[1] instanceof PhpTypedElement) {
final Project project = holder.getProject();
final PhpType arrayType = OpenapiResolveUtil.resolveType((PhpTypedElement) arguments[1], project);
final Set<String> arrayTypes = arrayType == null ? null : arrayType.filterUnknown().getTypes();
if (arrayTypes != null && arrayTypes.size() == 1) {
final PhpType itemType = OpenapiResolveUtil.resolveType((PhpTypedElement) arguments[0], project);
final Set<String> itemTypes = itemType == null ? null : itemType.filterUnknown().getTypes();
if (itemTypes != null && itemTypes.size() == 1) {
final boolean matching = this.areTypesMatching(itemTypes.iterator().next(), arrayTypes.iterator().next());
if (matching) {
return;
}
}
}
}
/* general case: we need the third argument */
final String replacement = String.format("%s%s(%s, %s, true)", reference.getImmediateNamespaceName(), functionName, arguments[0].getText(), arguments[1].getText());
holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(message), new MakeSearchTypeSensitiveFix(replacement));
}
}
}
private boolean areTypesMatching(@NotNull String itemType, @NotNull String arrayType) {
boolean result = false;
if (!itemType.isEmpty()) {
result = arrayType.equals((itemType.charAt(0) == '\\' ? itemType : '\\' + itemType) + "[]");
}
return result;
}
};
}
use of com.jetbrains.php.lang.psi.elements.PhpTypedElement in project phpinspectionsea by kalessil.
the class MustReturnSpecifiedTypeStrategy method apply.
public static void apply(@NotNull PhpType allowedTypes, @NotNull Method method, @NotNull ProblemsHolder holder) {
final PsiElement returnType = OpenapiElementsUtil.getReturnType(method);
if (returnType != null) {
/* case: return type has ben specified */
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) returnType, holder.getProject());
if (resolved != null) {
final PhpType normalizedType = new PhpType();
resolved.filterUnknown().getTypes().forEach(t -> normalizedType.add(Types.getType(t)));
if (!normalizedType.isEmpty() && !PhpType.isSubType(normalizedType, allowedTypes)) {
final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
if (nameNode != null) {
final PhpType withoutStatic = allowedTypes.filter((new PhpType()).add(Types.strStatic));
holder.registerProblem(nameNode, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), method.getName(), withoutStatic.toString(), normalizedType.toString()));
}
}
}
} else {
final Collection<PhpReturn> returns = PsiTreeUtil.findChildrenOfType(method, PhpReturn.class);
if (returns.isEmpty()) {
/* case: the method doesn't return anything */
final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
if (nameNode != null) {
final PhpType withoutStatic = allowedTypes.filter((new PhpType()).add(Types.strStatic));
holder.registerProblem(nameNode, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), method.getName(), withoutStatic.toString(), ""));
}
} else {
/* case: method returns non-compatible type */
final PhpType withoutStatic = allowedTypes.filter((new PhpType()).add(Types.strStatic));
final Project project = holder.getProject();
for (final PhpReturn expression : returns) {
final PhpType normalizedType = new PhpType();
final PsiElement returnValue = ExpressionSemanticUtil.getExpressionTroughParenthesis(ExpressionSemanticUtil.getReturnValue(expression));
if (returnValue instanceof PhpTypedElement) {
/* previously we had an issue with https://youtrack.jetbrains.com/issue/WI-31249 here */
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) returnValue, project);
if (resolved != null) {
resolved.filterUnknown().getTypes().forEach(t -> normalizedType.add(Types.getType(t)));
/* case: resolve has failed or resolved types are compatible */
if (normalizedType.isEmpty() || PhpType.isSubType(normalizedType, allowedTypes)) {
continue;
} else /* case: closure or anonymous class */
if (method != ExpressionSemanticUtil.getScope(expression)) {
continue;
}
}
}
holder.registerProblem(expression, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), method.getName(), withoutStatic.toString(), normalizedType.toString()));
}
returns.clear();
}
}
}
use of com.jetbrains.php.lang.psi.elements.PhpTypedElement in project phpinspectionsea by kalessil.
the class NullableArgumentComparisonStrategy method apply.
public static boolean apply(@NotNull BinaryExpression expression, @NotNull ProblemsHolder holder) {
boolean result = false;
final IElementType operator = expression.getOperationType();
if (mapping.containsKey(operator)) {
PsiElement parent = expression.getParent();
while (parent instanceof ParenthesizedExpression) {
parent = parent.getParent();
}
final PsiElement argument = expression.getLeftOperand();
final PsiElement value = expression.getRightOperand();
if (parent instanceof UnaryExpression && argument instanceof PhpTypedElement && value != null) {
final UnaryExpression target = (UnaryExpression) parent;
if (OpenapiTypesUtil.is(target.getOperation(), PhpTokenTypes.opNOT)) {
final PhpType type = OpenapiResolveUtil.resolveType((PhpTypedElement) argument, holder.getProject());
if (type != null && !type.hasUnknown()) {
final Set<String> types = new HashSet<>();
type.getTypes().forEach(t -> types.add(Types.getType(t)));
if (types.contains(Types.strNull) || types.contains(Types.strBoolean)) {
final String replacement = String.format("%s %s %s", argument.getText(), mapping.get(operator), value.getText());
holder.registerProblem(target, MessagesPresentationUtil.prefixWithEa(String.format(messagePattern, replacement)), new NullableArgumentComparisonFix(replacement));
result = true;
}
types.clear();
}
}
}
}
return result;
}
Aggregations