use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class IssetAndNullComparisonStrategy method apply.
public static boolean apply(@NotNull List<PsiElement> conditions, @NotNull ProblemsHolder holder) {
/* first ensure that we have null identity checks at all */
final Map<PsiElement, PsiElement> nullTestSubjects = new HashMap<>();
for (final PsiElement oneCondition : conditions) {
if (oneCondition instanceof BinaryExpression) {
final BinaryExpression expression = (BinaryExpression) oneCondition;
/* we need only !== and === operations */
final IElementType operator = expression.getOperationType();
if (operator != PhpTokenTypes.opIDENTICAL && operator != PhpTokenTypes.opNOT_IDENTICAL) {
continue;
}
/* quickly check if any operands is a constant */
final PsiElement left = expression.getLeftOperand();
final PsiElement right = expression.getRightOperand();
if (!(left instanceof ConstantReference) && !(right instanceof ConstantReference)) {
continue;
}
/* store null test subjects */
if (PhpLanguageUtil.isNull(right)) {
if (null != left) {
nullTestSubjects.put(expression, left);
}
continue;
}
if (PhpLanguageUtil.isNull(left)) {
if (null != right) {
nullTestSubjects.put(expression, right);
}
// continue;
}
}
}
if (0 == nullTestSubjects.size()) {
return false;
}
boolean hasReportedExpressions = false;
for (final PsiElement oneCondition : conditions) {
/* do not process null identity checks */
if (nullTestSubjects.containsKey(oneCondition)) {
continue;
}
/* unwrap ! and () */
PsiElement issetCandidate = oneCondition;
if (issetCandidate instanceof UnaryExpression) {
final PsiElement notOperatorCandidate = ((UnaryExpression) issetCandidate).getOperation();
if (null != notOperatorCandidate && notOperatorCandidate.getNode().getElementType() == PhpTokenTypes.opNOT) {
PsiElement invertedValue = ((UnaryExpression) issetCandidate).getValue();
invertedValue = ExpressionSemanticUtil.getExpressionTroughParenthesis(invertedValue);
if (null == invertedValue) {
continue;
}
issetCandidate = invertedValue;
}
}
if (!(issetCandidate instanceof PhpIsset) || 0 == ((PhpIsset) issetCandidate).getVariables().length) {
continue;
}
/* process isset constructions */
for (final PsiElement issetArgument : ((PhpIsset) issetCandidate).getVariables()) {
/* compare with know null identity checked subjects */
for (final Map.Entry<PsiElement, PsiElement> nullTestPair : nullTestSubjects.entrySet()) {
if (!OpeanapiEquivalenceUtil.areEqual(nullTestPair.getValue(), issetArgument)) {
continue;
}
hasReportedExpressions = true;
final PsiElement nullTestExpression = nullTestPair.getKey();
final String message = messagePattern.replace("%e%", nullTestExpression.getText());
holder.registerProblem(nullTestExpression, message, ProblemHighlightType.WEAK_WARNING);
}
}
}
nullTestSubjects.clear();
return hasReportedExpressions;
}
use of com.jetbrains.php.lang.psi.elements.BinaryExpression 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.BinaryExpression in project phpinspectionsea by kalessil.
the class IsIterableCanBeUsedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
final String functionName = reference.getName();
if (functionName != null && functionName.equals("is_array")) {
final boolean isTargetVersion = PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP710);
if (isTargetVersion) {
final PsiElement[] arguments = reference.getParameters();
final PsiElement parent = reference.getParent();
if (parent instanceof BinaryExpression && arguments.length == 1) {
final BinaryExpression binary = (BinaryExpression) parent;
final IElementType operation = binary.getOperationType();
if (operation == PhpTokenTypes.opOR) {
/* find the high-level binary expression */
BinaryExpression context = binary;
while (context instanceof BinaryExpression) {
PsiElement up = context.getParent();
while (up instanceof ParenthesizedExpression) {
up = up.getParent();
}
if (up instanceof BinaryExpression && ((BinaryExpression) up).getOperationType() == PhpTokenTypes.opOR) {
context = (BinaryExpression) up;
} else {
break;
}
}
/* check the pattern */
final List<PsiElement> fragments = this.extract(context, PhpTokenTypes.opOR);
if (!fragments.isEmpty()) {
if (fragments.size() > 1) {
for (final PsiElement fragment : fragments) {
if (fragment != reference && fragment instanceof BinaryExpression) {
final BinaryExpression candidate = (BinaryExpression) fragment;
if (candidate.getOperationType() == PhpTokenTypes.kwINSTANCEOF) {
final PsiElement clazz = candidate.getRightOperand();
if (clazz instanceof ClassReference && "Traversable".equals(((ClassReference) clazz).getName())) {
final PsiElement subject = candidate.getLeftOperand();
if (subject != null && OpenapiEquivalenceUtil.areEqual(subject, arguments[0])) {
final String argument = subject.getText();
holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(message), argument, argument, argument));
break;
}
}
}
}
}
}
fragments.clear();
}
}
}
}
}
}
@NotNull
private List<PsiElement> extract(@NotNull BinaryExpression binary, @Nullable IElementType operator) {
final List<PsiElement> result = new ArrayList<>();
if (binary.getOperationType() == operator) {
Stream.of(binary.getLeftOperand(), binary.getRightOperand()).filter(Objects::nonNull).map(ExpressionSemanticUtil::getExpressionTroughParenthesis).forEach(expression -> {
if (expression instanceof BinaryExpression) {
result.addAll(this.extract((BinaryExpression) expression, operator));
} else {
result.add(expression);
}
});
} else {
result.add(binary);
}
return result;
}
};
}
use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class SubStrShortHandUsageInspector 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 && substringFunctions.contains(functionName)) {
final PsiElement[] arguments = reference.getParameters();
if ((arguments.length == 3 || arguments.length == 4) && arguments[2] instanceof BinaryExpression) {
/* check if 3rd argument is "strlen($search) - strlen(...)": "strlen($search)" is not needed */
final BinaryExpression binary = (BinaryExpression) arguments[2];
if (binary.getOperationType() == PhpTokenTypes.opMINUS) {
final PsiElement left = binary.getLeftOperand();
final PsiElement right = binary.getRightOperand();
if (right != null && OpenapiTypesUtil.isFunctionReference(left)) {
final FunctionReference leftCall = (FunctionReference) left;
final String leftName = leftCall.getName();
if (leftName != null && lengthFunctions.contains(leftName)) {
final PsiElement[] leftArguments = leftCall.getParameters();
if (leftArguments.length == 1 && OpenapiEquivalenceUtil.areEqual(leftArguments[0], arguments[0])) {
final PsiElement startOffset = arguments[1];
if (OpenapiEquivalenceUtil.areEqual(right, startOffset)) {
/* case: third parameter is not needed at all */
holder.registerProblem(arguments[2], String.format(MessagesPresentationUtil.prefixWithEa(patternDropLength), arguments[2].getText()), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new DropThirdParameterFix(holder.getProject(), reference));
} else if (OpenapiTypesUtil.isNumber(startOffset) && OpenapiTypesUtil.isNumber(right)) {
try {
int offset = Integer.parseInt(startOffset.getText()) - Integer.parseInt(right.getText());
if (offset < 0) {
/* case: third parameter can be simplified */
holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(patternSimplifyLength), offset), new SimplifyFix(String.valueOf(offset)));
} else {
/* case: third parameter is not needed at all */
holder.registerProblem(arguments[2], String.format(MessagesPresentationUtil.prefixWithEa(patternDropLength), arguments[2].getText()), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new DropThirdParameterFix(holder.getProject(), reference));
}
} catch (final NumberFormatException expected) {
// return;
}
}
}
}
}
}
}
}
}
};
}
use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class StrContainsCanBeUsedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
final String functionName = reference.getName();
if (functionName != null && (functionName.equals("strpos") || functionName.equals("mb_strpos"))) {
final boolean isTargetVersion = PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP800);
if (isTargetVersion) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 2) {
final PsiElement context = reference.getParent();
if (context instanceof BinaryExpression) {
final BinaryExpression binary = (BinaryExpression) context;
final IElementType operation = binary.getOperationType();
final boolean isTarget = (operation == PhpTokenTypes.opNOT_IDENTICAL || operation == PhpTokenTypes.opIDENTICAL) && PhpLanguageUtil.isFalse(OpenapiElementsUtil.getSecondOperand(binary, reference));
if (isTarget) {
final String replacement = String.format("%s%sstr_contains(%s, %s)", operation == PhpTokenTypes.opIDENTICAL ? "! " : "", reference.getImmediateNamespaceName(), arguments[0].getText(), arguments[1].getText());
holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(message), replacement), new UseStrContainsFix(replacement));
}
}
}
}
}
}
};
}
Aggregations