use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class IncrementDecrementOperationEquivalentInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
/* ensures we are not touching arrays only, not strings and not objects */
private boolean isArrayAccessOrString(@Nullable PhpPsiElement variable) {
if (variable instanceof ArrayAccessExpression) {
final PsiElement container = ((ArrayAccessExpression) variable).getValue();
if (container instanceof PhpTypedElement) {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) container, holder.getProject());
if (resolved != null) {
final Set<String> types = new HashSet<>();
resolved.filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
final boolean isArray = types.contains(Types.strArray) && !types.contains(Types.strString);
types.clear();
return !isArray;
}
}
}
return false;
}
@Override
public void visitPhpSelfAssignmentExpression(@NotNull SelfAssignmentExpression expression) {
final IElementType operation = expression.getOperationType();
final PhpPsiElement value = expression.getValue();
final PhpPsiElement variable = expression.getVariable();
if (null != value && null != operation && null != variable) {
if (operation == PhpTokenTypes.opPLUS_ASGN) {
if (value.getText().equals("1") && !isArrayAccessOrString(variable)) {
final String replacement = PREFER_PREFIX_STYLE ? ("++" + variable.getText()) : (variable.getText() + "++");
holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseIncrementFix(replacement));
}
} else if (operation == PhpTokenTypes.opMINUS_ASGN) {
if (value.getText().equals("1") && !isArrayAccessOrString(variable)) {
final String replacement = PREFER_PREFIX_STYLE ? ("--" + variable.getText()) : (variable.getText() + "--");
holder.registerProblem(expression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseDecrementFix(replacement));
}
}
}
}
@Override
public void visitPhpAssignmentExpression(@NotNull AssignmentExpression assignmentExpression) {
final PhpPsiElement variable = assignmentExpression.getVariable();
if (variable != null && assignmentExpression.getValue() instanceof BinaryExpression) {
final BinaryExpression value = (BinaryExpression) assignmentExpression.getValue();
/* operation and operands provided */
final PsiElement leftOperand = value.getLeftOperand();
final PsiElement rightOperand = value.getRightOperand();
final IElementType operation = value.getOperationType();
if (null == leftOperand || null == rightOperand || null == operation) {
return;
}
if (operation == PhpTokenTypes.opPLUS) {
/* plus operation: operand position NOT important */
if ((leftOperand.getText().equals("1") && OpenapiEquivalenceUtil.areEqual(rightOperand, variable)) || (rightOperand.getText().equals("1") && OpenapiEquivalenceUtil.areEqual(leftOperand, variable))) {
if (!isArrayAccessOrString(variable)) {
final String replacement = PREFER_PREFIX_STYLE ? ("++" + variable.getText()) : (variable.getText() + "++");
holder.registerProblem(assignmentExpression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseIncrementFix(replacement));
}
}
} else if (operation == PhpTokenTypes.opMINUS) {
/* minus operation: operand position IS important */
if (rightOperand.getText().equals("1") && OpenapiEquivalenceUtil.areEqual(leftOperand, variable) && !isArrayAccessOrString(variable)) {
final String replacement = PREFER_PREFIX_STYLE ? ("--" + variable.getText()) : (variable.getText() + "--");
holder.registerProblem(assignmentExpression, MessagesPresentationUtil.prefixWithEa(patternMessage.replace("%e%", replacement)), new UseDecrementFix(replacement));
}
}
}
}
};
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class MisplacedOperatorStrategy method apply.
public static boolean apply(@NotNull BinaryExpression expression, @NotNull ProblemsHolder holder) {
final PsiElement parent = expression.getParent().getParent();
/* basic operator filter */
if (parent instanceof FunctionReference && operations.contains(expression.getOperationType())) {
final FunctionReference call = (FunctionReference) parent;
final PsiElement[] arguments = call.getParameters();
final PsiElement candidate = arguments.length > 0 ? arguments[arguments.length - 1] : null;
/* BO should be the last parameter of a call in logical contexts */
if (candidate == expression && ExpressionSemanticUtil.isUsedAsLogicalOperand(parent)) {
final PsiElement resolved = OpenapiResolveUtil.resolveReference(call);
if (resolved instanceof Function) {
/* resolve the last parameter types: if bool not defined implicitly, continue */
final Function function = (Function) resolved;
final Parameter[] params = function.getParameters();
if (params.length >= arguments.length) {
final Parameter parameter = params[arguments.length - 1];
final Set<String> types = new HashSet<>();
parameter.getType().filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
if (!types.contains(Types.strBoolean)) {
final PsiElement rightOperand = expression.getRightOperand();
final PsiElement leftOperand = expression.getLeftOperand();
if (leftOperand != null && rightOperand instanceof PhpTypedElement) {
final Project project = holder.getProject();
final PhpType allowedTypes = function.getType().global(project).filterUnknown();
final PhpType operandTypes = ((PhpTypedElement) rightOperand).getType().global(project).filterUnknown();
final PsiElement operator = expression.getOperation();
if (operator != null && allowedTypes.getTypes().containsAll(operandTypes.getTypes())) {
final String replacement = "%c% %o% %r%".replace("%r%", rightOperand.getText()).replace("%o%", operator.getText()).replace("%c%", call.getText()).replace(expression.getText(), leftOperand.getText());
holder.registerProblem(operator, MessagesPresentationUtil.prefixWithEa(message), new MisplacedOperatorFix(holder.getProject(), replacement, call));
return true;
}
}
}
types.clear();
}
}
}
}
return false;
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType 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;
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class ClassMethodNameMatchesFieldNameInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpMethod(@NotNull Method method) {
final PhpClass clazz = method.getContainingClass();
if (clazz != null && !clazz.isInterface()) {
final Field field = OpenapiResolveUtil.resolveField(clazz, method.getName());
if (field != null) {
final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
final PhpType resolvedType = OpenapiResolveUtil.resolveType(field, holder.getProject());
if (resolvedType != null && nameNode != null) {
final PhpType knownType = resolvedType.filterUnknown();
if (knownType.isEmpty()) {
holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageFieldType));
} else {
final boolean isCallable = knownType.getTypes().stream().anyMatch(t -> Types.getType(t).equals(Types.strCallable));
if (isCallable) {
holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageMatches));
}
}
}
}
}
}
};
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class LoopWhichDoesNotLoopInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpForeach(@NotNull ForeachStatement loop) {
final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
if (!isBlade && this.isNotLooping(loop)) {
/* false-positive: return first element from generator, iterable and co */
final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(loop);
final PsiElement last = body == null ? null : ExpressionSemanticUtil.getLastStatement(body);
if (last != null && !OpenapiTypesUtil.isThrowExpression(last)) {
final PsiElement source = loop.getArray();
if (source instanceof PhpTypedElement) {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) source, holder.getProject());
final boolean isValid = resolved != null && resolved.filterUnknown().getTypes().stream().anyMatch(type -> foreachExceptions.contains(Types.getType(type)));
if (isValid) {
return;
}
}
}
holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
}
}
@Override
public void visitPhpFor(@NotNull For loop) {
final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
if (!isBlade && this.isNotLooping(loop)) {
holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
}
}
@Override
public void visitPhpWhile(@NotNull While loop) {
final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
if (!isBlade && this.isNotLooping(loop)) {
holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
}
}
@Override
public void visitPhpDoWhile(@NotNull DoWhile loop) {
final boolean isBlade = holder.getFile().getName().endsWith(".blade.php");
if (!isBlade && this.isNotLooping(loop)) {
holder.registerProblem(loop.getFirstChild(), MessagesPresentationUtil.prefixWithEa(message));
}
}
private boolean isNotLooping(@NotNull PhpPsiElement loop) {
final GroupStatement body = ExpressionSemanticUtil.getGroupStatement(loop);
if (null == body) {
return false;
}
final PsiElement lastExpression = ExpressionSemanticUtil.getLastStatement(body);
final boolean isLoopTerminatedWithLastExpression = lastExpression instanceof PhpBreak || lastExpression instanceof PhpReturn || OpenapiTypesUtil.isThrowExpression(lastExpression);
/* loop is empty or terminates on first iteration */
if (null != lastExpression && !isLoopTerminatedWithLastExpression) {
return false;
}
/* detect continue statements, which makes the loop looping */
for (final PhpContinue expression : PsiTreeUtil.findChildrenOfType(body, PhpContinue.class)) {
int nestingLevel = 0;
PsiElement parent = expression.getParent();
while (null != parent && !(parent instanceof Function) && !(parent instanceof PsiFile)) {
if (OpenapiTypesUtil.isLoop(parent)) {
++nestingLevel;
if (parent == loop) {
/* extract level of continuation from the statement */
int continueLevel = 1;
final PsiElement argument = expression.getArgument();
if (null != argument) {
try {
continueLevel = Integer.parseInt(argument.getText());
} catch (final NumberFormatException notParsed) {
continueLevel = 1;
}
}
/* matched continue for the current loop */
if (continueLevel == nestingLevel) {
return false;
}
}
}
parent = parent.getParent();
}
}
return true;
}
};
}
Aggregations