use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.
the class StringCaseManipulationInspector 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 && functions.containsKey(functionName)) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 2) {
final PsiElement first = this.getSubject(arguments[0]);
final PsiElement second = this.getSubject(arguments[1]);
if (first != null || second != null) {
final String replacement = "%f%(%a1%, %a2%)".replace("%a2%", (second == null ? arguments[1] : second).getText()).replace("%a1%", (first == null ? arguments[0] : first).getText()).replace("%f%", functions.get(functionName));
holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new SimplifyFix(replacement));
}
}
}
}
@Nullable
private PsiElement getSubject(@NotNull PsiElement expression) {
PsiElement result = null;
if (OpenapiTypesUtil.isFunctionReference(expression)) {
final FunctionReference reference = (FunctionReference) expression;
final String functionName = reference.getName();
if (functionName != null && innerFunctions.contains(functionName)) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 1) {
result = arguments[0];
}
}
}
return result;
}
};
}
use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.
the class JsonEncodingApiUsageInspector 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) {
if (functionName.equals("json_decode") && this.isFromRootNamespace(reference)) {
final PsiElement[] arguments = reference.getParameters();
if (HARDEN_DECODING_RESULT_TYPE && arguments.length == 1) {
final String replacement = String.format("%sjson_decode(%s, %s)", reference.getImmediateNamespaceName(), arguments[0].getText(), DECODE_AS_ARRAY ? "true" : "false");
holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageResultType), DECODE_AS_ARRAY ? new DecodeIntoArrayFix(replacement) : new DecodeIntoObjectFix(replacement));
}
if (HARDEN_ERRORS_HANDLING && arguments.length > 0 && PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP730)) {
final boolean hasFlag = arguments.length >= 4 && this.hasStricterHandlingFlags(arguments[3]);
if (!hasFlag) {
final String replacement = String.format("%sjson_decode(%s, %s, %s, %s)", reference.getImmediateNamespaceName(), arguments[0].getText(), arguments.length > 1 ? arguments[1].getText() : (HARDEN_DECODING_RESULT_TYPE && DECODE_AS_ARRAY ? "true" : "false"), arguments.length > 2 ? arguments[2].getText() : "512", arguments.length > 3 ? "JSON_THROW_ON_ERROR | " + arguments[3].getText() : "JSON_THROW_ON_ERROR");
holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageErrorsHandling), new HardenErrorsHandlingFix(replacement));
}
}
} else if (functionName.equals("json_encode") && this.isFromRootNamespace(reference)) {
if (HARDEN_ERRORS_HANDLING && PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP730)) {
final PsiElement[] arguments = reference.getParameters();
final boolean hasFlag = arguments.length >= 2 && this.hasStricterHandlingFlags(arguments[1]);
if (!hasFlag && arguments.length > 0) {
final String replacement;
if (arguments.length > 2) {
replacement = String.format("%sjson_encode(%s, %s, %s)", reference.getImmediateNamespaceName(), arguments[0].getText(), "JSON_THROW_ON_ERROR | " + arguments[1].getText(), arguments[2].getText());
} else {
replacement = String.format("%sjson_encode(%s, %s)", reference.getImmediateNamespaceName(), arguments[0].getText(), arguments.length > 1 ? "JSON_THROW_ON_ERROR | " + arguments[1].getText() : "JSON_THROW_ON_ERROR");
}
holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageErrorsHandling), new HardenErrorsHandlingFix(replacement));
}
}
}
}
}
private boolean hasStricterHandlingFlags(@NotNull PsiElement argument) {
boolean hasFlag = false;
final Set<PsiElement> options = argument instanceof ConstantReference ? new HashSet<>(Collections.singletonList(argument)) : PossibleValuesDiscoveryUtil.discover(argument);
if (options.size() == 1) {
final PsiElement option = options.iterator().next();
if (OpenapiTypesUtil.isNumber(option)) {
/* properly resolved value */
hasFlag = strictHandlingFlags.containsValue(option.getText());
} else if (option instanceof ConstantReference) {
/* constant value resolution fails for some reason */
hasFlag = strictHandlingFlags.containsKey(((ConstantReference) option).getName());
} else {
/* a complex case like local variable or implicit flags combination */
hasFlag = PsiTreeUtil.findChildrenOfType(option, ConstantReference.class).stream().anyMatch(r -> strictHandlingFlags.containsKey(r.getName()));
}
}
options.clear();
return hasFlag;
}
};
}
use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.
the class StringNormalizationInspector 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 PsiElement[] arguments = reference.getParameters();
if (arguments.length > 0 && OpenapiTypesUtil.isFunctionReference(arguments[0])) {
final FunctionReference innerCall = (FunctionReference) arguments[0];
final String innerCallName = innerCall.getName();
if (innerCallName != null) {
final PsiElement[] innerArguments = innerCall.getParameters();
if (innerArguments.length > 0) {
if (lengthManipulation.contains(functionName) && caseManipulation.contains(innerCallName)) {
final boolean isTarget = !functionName.endsWith("trim") || arguments.length == 1 || (arguments[1] instanceof StringLiteralExpression && !regexTrimmedCharacters.matcher(arguments[1].getText()).matches());
if (isTarget) {
final String theString = innerArguments[0].getText();
final String newInnerCall = reference.getText().replace(arguments[0].getText(), theString);
final String replacement = innerCall.getText().replace(theString, newInnerCall);
holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(String.format(patternInvertedNesting, replacement)), new NormalizationFix(replacement));
}
} else if (caseManipulation.contains(functionName) && caseManipulation.contains(innerCallName)) {
if (functionName.equals(innerCallName)) {
holder.registerProblem(innerCall, MessagesPresentationUtil.prefixWithEa(String.format(patternSenselessNesting, innerCallName)), new NormalizationFix(innerArguments[0].getText()));
} else if (!innerCaseManipulation.contains(innerCallName)) {
/* false-positives: ucwords with 2 arguments */
final boolean isTarget = !innerCallName.equals("ucwords") || innerArguments.length == 1;
if (isTarget) {
holder.registerProblem(innerCall, MessagesPresentationUtil.prefixWithEa(String.format(patternSenselessNesting, innerCallName)), new NormalizationFix(innerArguments[0].getText()));
}
}
}
}
}
}
}
}
};
}
use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.
the class SubStrUsedAsStrPosInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
/* dropped pattern: '$string[0] === '?'' -> 'substr(...) === 0' */
@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) {
/* checking 2nd and 3rd arguments is not needed/simplified:
* - 2nd re-used as it is (should be a positive number!)
* - 3rd is not important, as we'll rely on parent comparison operand instead
*/
final String index = arguments[1].getText();
if (OpenapiTypesUtil.isNumber(arguments[1]) && index.equals("0")) {
if (!OpenapiTypesUtil.isFunctionReference(arguments[2]) || lengthFunctions.contains(((FunctionReference) arguments[2]).getName())) {
/* prepare variables, so we could properly process polymorphic pattern */
PsiElement highLevelCall = reference;
PsiElement parentExpression = reference.getParent();
if (parentExpression instanceof ParameterList) {
parentExpression = parentExpression.getParent();
}
/* if the call wrapped with case manipulation, propose to use stripos */
boolean caseManipulated = false;
if (OpenapiTypesUtil.isFunctionReference(parentExpression)) {
final FunctionReference parentCall = (FunctionReference) parentExpression;
final PsiElement[] parentArguments = parentCall.getParameters();
final String parentName = parentCall.getName();
if (parentName != null && parentArguments.length == 1 && outerFunctions.contains(parentName)) {
caseManipulated = true;
highLevelCall = parentExpression;
parentExpression = parentExpression.getParent();
}
}
/* check parent expression, to ensure pattern matched */
if (parentExpression instanceof BinaryExpression) {
final BinaryExpression parent = (BinaryExpression) parentExpression;
if (OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(parent.getOperationType())) {
final PsiElement secondOperand = OpenapiElementsUtil.getSecondOperand(parent, highLevelCall);
final PsiElement operationNode = parent.getOperation();
if (secondOperand != null && operationNode != null) {
final String operator = operationNode.getText();
final boolean isMbFunction = functionName.equals("mb_substr");
final boolean hasEncoding = isMbFunction && arguments.length == 4;
final String call = String.format("%s%s(%s, %s%s)", reference.getImmediateNamespaceName(), (isMbFunction ? "mb_" : "") + (caseManipulated ? "stripos" : "strpos"), arguments[0].getText(), secondOperand.getText(), hasEncoding ? (", " + arguments[3].getText()) : "");
final boolean isRegular = ComparisonStyle.isRegular();
final String replacement = String.format("%s %s %s", isRegular ? call : index, operator.length() == 2 ? (operator + '=') : operator, isRegular ? index : call);
holder.registerProblem(parentExpression, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseStringSearchFix(replacement));
}
}
}
}
}
}
}
}
};
}
use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.
the class ArrayUniqueCanBeUsedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
if (PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP720)) {
final String functionName = reference.getName();
if (functionName != null && functionName.equals("array_count_values")) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 1) {
final PsiElement context = reference.getParent().getParent();
if (OpenapiTypesUtil.isFunctionReference(context)) {
final String parentFunctionName = ((FunctionReference) context).getName();
if (parentFunctionName != null) {
if (parentFunctionName.equals("array_keys")) {
final String replacement = "array_values(array_unique(%a%))".replace("%a%", arguments[0].getText());
holder.registerProblem(context, MessagesPresentationUtil.prefixWithEa(messagePattern.replace("%e%", replacement)), new ReplaceFix(replacement));
} else if (parentFunctionName.equals("count")) {
final String replacement = "count(array_unique(%a%))".replace("%a%", arguments[0].getText());
holder.registerProblem(context, MessagesPresentationUtil.prefixWithEa(messagePattern.replace("%e%", replacement)), new ReplaceFix(replacement));
}
}
}
}
}
}
}
};
}
Aggregations