use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class RandomApiMigrationInspector 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) {
final PhpLanguageLevel php = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
String suggestion = getMapping(php).get(functionName);
if (suggestion != null) {
/* random_int needs 2 parameters always, so check if mt_rand can be suggested */
if (reference.getParameters().length != 2 && suggestion.equals("random_int")) {
if (functionName.equals("rand")) {
suggestion = "mt_rand";
} else {
return;
}
}
final String message = messagePattern.replace("%o%", functionName).replace("%n%", suggestion);
holder.registerProblem(reference, message, new TheLocalFix(suggestion));
}
}
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class CascadeStringReplacementInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpReturn(@NotNull PhpReturn returnStatement) {
final FunctionReference functionCall = this.getFunctionReference(returnStatement);
if (functionCall != null) {
this.analyze(functionCall, returnStatement);
}
}
@Override
public void visitPhpAssignmentExpression(@NotNull AssignmentExpression assignmentExpression) {
final FunctionReference functionCall = this.getFunctionReference(assignmentExpression);
if (functionCall != null) {
this.analyze(functionCall, assignmentExpression);
}
}
private void analyze(@NotNull FunctionReference functionCall, @NotNull PsiElement expression) {
final PsiElement[] arguments = functionCall.getParameters();
if (arguments.length == 3) {
/* case: cascading replacements */
final AssignmentExpression previous = this.getPreviousAssignment(expression);
final FunctionReference previousCall = previous == null ? null : this.getFunctionReference(previous);
if (previousCall != null) {
final PsiElement transitionVariable = previous.getVariable();
if (transitionVariable instanceof Variable && arguments[2] instanceof Variable) {
final Variable callSubject = (Variable) arguments[2];
final Variable previousVariable = (Variable) transitionVariable;
final PsiElement callResultStorage = expression instanceof AssignmentExpression ? ((AssignmentExpression) expression).getVariable() : callSubject;
if (callResultStorage != null && callSubject.getName().equals(previousVariable.getName()) && OpenapiEquivalenceUtil.areEqual(transitionVariable, callResultStorage) && this.canMergeArguments(functionCall, previousCall)) {
holder.registerProblem(functionCall, MessagesPresentationUtil.prefixWithEa(messageCascading), new MergeStringReplaceCallsFix(holder.getProject(), functionCall, previousCall, USE_SHORT_ARRAYS_SYNTAX));
}
}
}
/* case: nested replacements */
this.checkNestedCalls(holder.getProject(), arguments[2], functionCall);
/* case: search simplification */
if (arguments[1] instanceof StringLiteralExpression) {
final PsiElement search = arguments[0];
if (search instanceof ArrayCreationExpression) {
this.checkForSimplification((ArrayCreationExpression) search);
}
}
}
}
private void checkForSimplification(@NotNull ArrayCreationExpression candidate) {
final Set<String> replacements = new HashSet<>();
for (final PsiElement oneReplacement : candidate.getChildren()) {
if (oneReplacement instanceof PhpPsiElement) {
final PhpPsiElement item = ((PhpPsiElement) oneReplacement).getFirstPsiChild();
if (!(item instanceof StringLiteralExpression)) {
replacements.clear();
return;
}
replacements.add(item.getText());
}
}
if (replacements.size() == 1) {
holder.registerProblem(candidate, MessagesPresentationUtil.prefixWithEa(messageReplacements), ProblemHighlightType.WEAK_WARNING, new SimplifyReplacementFix(replacements.iterator().next()));
}
replacements.clear();
}
private void checkNestedCalls(@NotNull Project project, @NotNull PsiElement callCandidate, @NotNull FunctionReference parentCall) {
if (OpenapiTypesUtil.isFunctionReference(callCandidate)) {
final FunctionReference functionCall = (FunctionReference) callCandidate;
final String functionName = functionCall.getName();
if (functionName != null && functionName.equals("str_replace") && this.canMergeArguments(functionCall, parentCall)) {
holder.registerProblem(callCandidate, MessagesPresentationUtil.prefixWithEa(messageNesting), new MergeStringReplaceCallsFix(project, parentCall, functionCall, USE_SHORT_ARRAYS_SYNTAX));
}
}
}
private boolean canMergeArguments(@NotNull FunctionReference call, @NotNull FunctionReference previousCall) {
final PsiElement[] arguments = call.getParameters();
final PsiElement[] previousArguments = previousCall.getParameters();
// If an argument is array (non-implicit), we need PHP 7.4+ for QF
final boolean haveArrayType = Stream.of(arguments[0], arguments[1], previousArguments[0], previousArguments[1]).filter(a -> a instanceof PhpTypedElement && !(a instanceof ArrayCreationExpression)).anyMatch(a -> {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) a, holder.getProject());
if (resolved != null) {
final Set<String> types = resolved.filterUnknown().getTypes().stream().map(Types::getType).collect(Collectors.toSet());
return types.contains(Types.strArray) && !types.contains(Types.strString);
}
return false;
});
if (haveArrayType) {
return PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP740);
}
return true;
}
@Nullable
private FunctionReference getFunctionReference(@NotNull AssignmentExpression assignment) {
FunctionReference result = null;
final PsiElement value = ExpressionSemanticUtil.getExpressionTroughParenthesis(assignment.getValue());
if (OpenapiTypesUtil.isFunctionReference(value)) {
final String functionName = ((FunctionReference) value).getName();
if (functionName != null && functionName.equals("str_replace")) {
result = (FunctionReference) value;
}
}
return result;
}
@Nullable
private FunctionReference getFunctionReference(@NotNull PhpReturn phpReturn) {
FunctionReference result = null;
final PsiElement value = ExpressionSemanticUtil.getExpressionTroughParenthesis(ExpressionSemanticUtil.getReturnValue(phpReturn));
if (OpenapiTypesUtil.isFunctionReference(value)) {
final String functionName = ((FunctionReference) value).getName();
if (functionName != null && functionName.equals("str_replace")) {
result = (FunctionReference) value;
}
}
return result;
}
@Nullable
private AssignmentExpression getPreviousAssignment(@NotNull PsiElement returnOrAssignment) {
/* get previous non-comment, non-php-doc expression */
PsiElement previous = null;
if (returnOrAssignment instanceof PhpReturn) {
previous = ((PhpReturn) returnOrAssignment).getPrevPsiSibling();
} else if (returnOrAssignment instanceof AssignmentExpression) {
previous = returnOrAssignment.getParent().getPrevSibling();
}
while (previous != null && !(previous instanceof PhpPsiElement)) {
previous = previous.getPrevSibling();
}
while (previous instanceof PhpDocComment) {
previous = ((PhpDocComment) previous).getPrevPsiSibling();
}
/* grab the target assignment */
final AssignmentExpression result;
if (previous != null && previous.getFirstChild() instanceof AssignmentExpression) {
result = (AssignmentExpression) previous.getFirstChild();
} else {
result = null;
}
return result;
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class FixedTimeStartWithInspector 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 && mapping.containsKey(functionName)) {
final PsiElement parent = reference.getParent();
if (parent instanceof BinaryExpression) {
final BinaryExpression binary = (BinaryExpression) parent;
final IElementType operator = binary.getOperationType();
if (operator == PhpTokenTypes.opIDENTICAL || operator == PhpTokenTypes.opNOT_IDENTICAL) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 2 && arguments[1] instanceof StringLiteralExpression) {
final PsiElement zeroCandidate = OpenapiElementsUtil.getSecondOperand(binary, reference);
if (zeroCandidate != null && zeroCandidate.getText().equals("0")) {
final StringLiteralExpression literal = (StringLiteralExpression) arguments[1];
if (literal.getFirstPsiChild() == null) {
final String replacement = String.format("%s(%s, %s, %s)", mapping.get(functionName), arguments[0].getText(), arguments[1].getText(), PhpStringUtil.unescapeText(literal.getContents(), literal.isSingleQuote()).length());
holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseFirstCharactersCompareFix(replacement));
}
}
}
}
}
}
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class StrEndsWithCanBeUsedInspector 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("substr") || functionName.equals("mb_substr"))) {
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();
if (operation == PhpTokenTypes.opNOT_IDENTICAL || operation == PhpTokenTypes.opIDENTICAL) {
final PsiElement limitArgument = this.extractLimitArgument(arguments[1]);
final PsiElement second = OpenapiElementsUtil.getSecondOperand(binary, reference);
if (second != null && limitArgument != null && OpenapiEquivalenceUtil.areEqual(second, limitArgument)) {
final String replacement = String.format("%s%sstr_ends_with(%s, %s)", operation == PhpTokenTypes.opNOT_IDENTICAL ? "! " : "", reference.getImmediateNamespaceName(), arguments[0].getText(), second.getText());
holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(message), replacement), new UseStrEndsWithFix(replacement));
}
}
}
}
}
}
}
@Nullable
private PsiElement extractLimitArgument(@Nullable PsiElement expression) {
if (expression instanceof UnaryExpression) {
final UnaryExpression unary = (UnaryExpression) expression;
if (OpenapiTypesUtil.is(unary.getOperation(), PhpTokenTypes.opMINUS)) {
final PsiElement argument = unary.getValue();
if (OpenapiTypesUtil.isFunctionReference(argument)) {
final FunctionReference reference = (FunctionReference) argument;
final String functionName = reference.getName();
if (functionName != null && (functionName.equals("strlen") || functionName.equals("mb_strlen"))) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 1) {
return arguments[0];
}
}
}
}
}
return null;
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class StrStrUsedAsStrPosInspector 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 && mapping.containsKey(functionName)) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length >= 2) {
/* checks implicit boolean comparison pattern */
final PsiElement parent = reference.getParent();
if (parent instanceof BinaryExpression) {
final BinaryExpression binary = (BinaryExpression) parent;
if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(binary.getOperationType())) {
final PsiElement secondOperand = OpenapiElementsUtil.getSecondOperand(binary, reference);
if (PhpLanguageUtil.isFalse(secondOperand)) {
final PsiElement operationNode = binary.getOperation();
if (operationNode != null) {
String operation = operationNode.getText();
operation = operation.length() == 2 ? operation + '=' : operation;
final String call = String.format("%s%s(%s, %s)", reference.getImmediateNamespaceName(), mapping.get(functionName), arguments[0].getText(), arguments[1].getText());
final boolean isRegular = ComparisonStyle.isRegular();
final String replacement = String.format("%s %s %s", isRegular ? call : "false", operation, isRegular ? "false" : call);
holder.registerProblem(binary, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseStrposFix(replacement));
return;
}
}
}
}
/* checks non-implicit boolean comparison patternS */
if (ExpressionSemanticUtil.isUsedAsLogicalOperand(reference)) {
final String operation = parent instanceof UnaryExpression ? "===" : "!==";
final String call = String.format("%s%s(%s, %s)", reference.getImmediateNamespaceName(), mapping.get(functionName), arguments[0].getText(), arguments[1].getText());
final boolean isRegular = ComparisonStyle.isRegular();
final String replacement = String.format("%s %s %s", isRegular ? call : "false", operation, isRegular ? "false" : call);
holder.registerProblem(parent instanceof UnaryExpression ? parent : reference, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseStrposFix(replacement));
}
}
}
}
};
}
Aggregations