use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class StrlenInEmptyStringCheckContextInspection 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 && (functionName.equals("strlen") || functionName.equals("mb_strlen"))) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length > 0 && ExpressionSemanticUtil.getBlockScope(reference) != null) {
boolean isMatchedPattern = false;
boolean isEmptyString = false;
PsiElement target = null;
/* check explicit numbers comparisons */
final PsiElement parent = reference.getParent();
if (parent instanceof BinaryExpression) {
final BinaryExpression binary = (BinaryExpression) parent;
final PsiElement left = binary.getLeftOperand();
final PsiElement secondOperand = OpenapiElementsUtil.getSecondOperand(binary, reference);
/* second operand should be a number */
if (OpenapiTypesUtil.isNumber(secondOperand)) {
final String number = secondOperand.getText();
/* check cases when comparing with 1 */
final IElementType operator = binary.getOperationType();
if (operator == PhpTokenTypes.opGREATER) {
isMatchedPattern = left == reference && number.equals("0");
target = binary;
isEmptyString = false;
} else if (operator == PhpTokenTypes.opLESS || operator == PhpTokenTypes.opGREATER_OR_EQUAL) {
isMatchedPattern = left == reference && number.equals("1");
target = binary;
isEmptyString = operator == PhpTokenTypes.opLESS;
}
/* check cases when checking equality to 0 */
if (!isMatchedPattern && OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(operator)) {
isMatchedPattern = number.equals("0");
target = binary;
isEmptyString = operator == PhpTokenTypes.opIDENTICAL || operator == PhpTokenTypes.opEQUAL;
}
}
}
/* checks NON-implicit boolean comparison patterns */
if (!isMatchedPattern && ExpressionSemanticUtil.isUsedAsLogicalOperand(reference)) {
isMatchedPattern = true;
target = reference;
final PsiElement operation = parent instanceof UnaryExpression ? ((UnaryExpression) parent).getOperation() : null;
if (operation != null) {
isEmptyString = OpenapiTypesUtil.is(operation, PhpTokenTypes.opNOT);
target = parent;
}
}
/* investigate possible issues */
if (isMatchedPattern) {
final boolean isRegular = ComparisonStyle.isRegular();
final String operator = (isEmptyString ? "=" : "!") + (this.canApplyIdentityOperator(arguments[0]) ? "==" : "=");
final String replacement = String.format(isRegular ? "%s %s ''" : "'' %s %s", isRegular ? arguments[0].getText() : operator, isRegular ? operator : arguments[0].getText());
holder.registerProblem(target, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new CompareToEmptyStringFix(replacement));
}
}
}
}
private boolean canApplyIdentityOperator(@NotNull PsiElement value) {
if (value instanceof PhpTypedElement) {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) value, holder.getProject());
if (resolved != null && resolved.size() == 1) {
return Types.strString.equals(Types.getType(resolved.getTypes().iterator().next()));
}
}
return false;
}
};
}
use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class UnclearOperationsPriorityStrategy method apply.
public static boolean apply(@NotNull BinaryExpression expression, @NotNull ProblemsHolder holder) {
final IElementType operator = expression.getOperationType();
final PsiElement parent = expression.getParent();
if (operator == PhpTokenTypes.opAND || operator == PhpTokenTypes.opOR) {
/* binary expressions, already wrapped into parentheses can be skipped */
if (parent instanceof BinaryExpression) {
final IElementType parentOperator = ((BinaryExpression) parent).getOperationType();
if (parentOperator != operator && (parentOperator == PhpTokenTypes.opAND || parentOperator == PhpTokenTypes.opOR)) {
final String replacement = '(' + expression.getText() + ')';
holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
return true;
}
} else /* assignment dramatically changing precedence */
if (OpenapiTypesUtil.isAssignment(parent) && !OpenapiTypesUtil.isStatementImpl(parent.getParent())) {
final String replacement = '(' + expression.getText() + ')';
holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
return true;
}
} else if (PhpTokenTypes.tsCOMPARE_OPS.contains(operator)) {
if (OpenapiTypesUtil.isAssignment(parent) && parent.getParent() instanceof If) {
final AssignmentExpression assignment = (AssignmentExpression) parent;
final PsiElement assignedValue = assignment.getValue();
if (assignedValue != null) {
final String value = assignedValue.getText();
final String replacement = assignment.getText().replace(value, '(' + value + ')');
holder.registerProblem(parent, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
return true;
}
} else if (PhpTokenTypes.tsCOMPARE_ORDER_OPS.contains(operator) && operator != PhpTokenTypes.opSPACESHIP) {
final PsiElement left = expression.getLeftOperand();
if (left instanceof UnaryExpression) {
final UnaryExpression candidate = (UnaryExpression) left;
if (OpenapiTypesUtil.is(candidate.getOperation(), PhpTokenTypes.opNOT)) {
final String value = candidate.getText();
final String replacement = expression.getText().replace(value, '(' + value + ')');
holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(message), new WrapItAsItIsFix(replacement));
return true;
}
}
}
}
return false;
}
use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class ChainedCallsStrategy method apply.
private static void apply(@NotNull MethodReference reference, @NotNull Map<MethodReference, String> nullTestedReferences, @NotNull ProblemsHolder holder) {
final PsiElement operator = OpenapiPsiSearchUtil.findResolutionOperator(reference);
if (OpenapiTypesUtil.is(operator, PhpTokenTypes.ARROW) && !OpenapiTypesUtil.isNullSafeMemberReferenceOperator(operator)) {
final PsiElement base = reference.getFirstPsiChild();
if (base instanceof FunctionReference) {
final FunctionReference baseCall = (FunctionReference) base;
final PhpType returnType = OpenapiResolveUtil.resolveType(baseCall, holder.getProject());
if (returnType != null) {
final String methodName = baseCall.getName();
for (final String resolvedType : returnType.filterUnknown().getTypes()) {
final String type = Types.getType(resolvedType);
if (type.equals(Types.strNull) || type.equals(Types.strVoid)) {
boolean isNullTested = false;
for (final Map.Entry<MethodReference, String> knownReference : nullTestedReferences.entrySet()) {
final String nullTestedMethodName = knownReference.getValue();
if (nullTestedMethodName != null && nullTestedMethodName.equals(methodName) && OpenapiEquivalenceUtil.areEqual(knownReference.getKey(), baseCall)) {
isNullTested = true;
break;
}
}
if (!isNullTested) {
holder.registerProblem(operator, MessagesPresentationUtil.prefixWithEa(message));
break;
}
}
}
}
}
/* collect null-tested references: only after main inspection! */
final PsiElement parent = reference.getParent();
if (parent instanceof BinaryExpression) {
final BinaryExpression parentExpression = (BinaryExpression) parent;
final IElementType operation = parentExpression.getOperationType();
if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(operation)) {
final PsiElement secondOperand = OpenapiElementsUtil.getSecondOperand(parentExpression, reference);
if (PhpLanguageUtil.isNull(secondOperand)) {
nullTestedReferences.put(reference, reference.getName());
}
} else if (operation == PhpTokenTypes.kwINSTANCEOF || PhpTokenTypes.tsSHORT_CIRCUIT_AND_OPS.contains(operation)) {
nullTestedReferences.put(reference, reference.getName());
}
} else if (ExpressionSemanticUtil.isUsedAsLogicalOperand(reference)) {
nullTestedReferences.put(reference, reference.getName());
}
}
}
use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class SuspiciousBinaryOperationInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpBinaryExpression(@NotNull BinaryExpression expression) {
final Collection<BooleanSupplier> callbacks = new ArrayList<>();
callbacks.add(() -> InstanceOfTraitStrategy.apply(expression, holder));
callbacks.add(() -> EqualsInAssignmentContextStrategy.apply(expression, holder));
callbacks.add(() -> GreaterOrEqualInHashElementStrategy.apply(expression, holder));
callbacks.add(() -> NullableArgumentComparisonStrategy.apply(expression, holder));
callbacks.add(() -> IdenticalOperandsStrategy.apply(expression, holder));
callbacks.add(() -> MisplacedOperatorStrategy.apply(expression, holder));
callbacks.add(() -> NullCoalescingOperatorCorrectnessStrategy.apply(expression, holder));
callbacks.add(() -> ConcatenationWithArrayStrategy.apply(expression, holder));
if (VERIFY_CONSTANTS_IN_CONDITIONS) {
callbacks.add(() -> HardcodedConstantValuesStrategy.apply(expression, holder));
}
if (VERIFY_UNCLEAR_OPERATIONS_PRIORITIES) {
callbacks.add(() -> UnclearOperationsPriorityStrategy.apply(expression, holder));
}
/* run through strategies until the first one fired something */
for (final BooleanSupplier strategy : callbacks) {
if (strategy.getAsBoolean()) {
break;
}
}
callbacks.clear();
}
};
}
use of com.jetbrains.php.lang.psi.elements.BinaryExpression in project phpinspectionsea by kalessil.
the class OpAssignShortSyntaxInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpAssignmentExpression(@NotNull AssignmentExpression assignment) {
final PsiElement value = ExpressionSemanticUtil.getExpressionTroughParenthesis(assignment.getValue());
if (value instanceof BinaryExpression) {
final BinaryExpression binary = (BinaryExpression) value;
final PsiElement operator = binary.getOperation();
if (operator != null) {
final PsiElement left = binary.getLeftOperand();
final PsiElement right = binary.getRightOperand();
final PsiElement variable = assignment.getVariable();
if (variable != null && left != null && right != null) {
final IElementType operation = operator.getNode().getElementType();
if (mapping.containsKey(operation)) {
final LinkedList<PsiElement> fragments = new LinkedList<>();
fragments.addLast(right);
PsiElement candidate = left;
while (candidate instanceof BinaryExpression) {
final BinaryExpression current = (BinaryExpression) candidate;
final PsiElement rightPart = current.getRightOperand();
if (rightPart != null) {
fragments.addLast(rightPart);
}
if (current.getOperationType() != operation) {
break;
}
candidate = current.getLeftOperand();
}
if (candidate != null && OpenapiEquivalenceUtil.areEqual(variable, candidate)) {
final boolean canShorten = (fragments.size() == 1 || chainingSafeOperators.contains(operation)) && fragments.stream().noneMatch(f -> f instanceof BinaryExpression);
if (canShorten) {
/* false-positives: string elements manipulation, causes a fatal error */
boolean isStringManipulation = false;
if (variable instanceof ArrayAccessExpression) {
final PsiElement stringCandidate = ((ArrayAccessExpression) variable).getValue();
if (stringCandidate instanceof PhpTypedElement) {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) stringCandidate, holder.getProject());
if (resolved != null && !resolved.hasUnknown()) {
isStringManipulation = resolved.getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strString));
}
}
}
if (!isStringManipulation) {
Collections.reverse(fragments);
final String replacement = String.format("%s %s= %s", candidate.getText(), operator.getText(), fragments.stream().map(PsiElement::getText).collect(Collectors.joining(" " + operator.getText() + " ")));
holder.registerProblem(assignment, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseShorthandOperatorFix(replacement));
}
}
}
fragments.clear();
}
}
}
}
}
};
}
Aggregations