Search in sources :

Example 31 with FunctionReference

use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.

the class AssertFileEqualsStrategy method apply.

public static boolean apply(@NotNull String methodName, @NotNull MethodReference reference, @NotNull ProblemsHolder holder) {
    boolean result = false;
    if (targetAssertions.contains(methodName)) {
        final PsiElement[] assertionArguments = reference.getParameters();
        if (assertionArguments.length > 1) {
            /* try extracting file_get_contents arguments */
            final List<PsiElement> extracts = Arrays.stream(assertionArguments).map(argument -> {
                PsiElement mappingResult = null;
                if (OpenapiTypesUtil.isFunctionReference(argument)) {
                    final FunctionReference candidate = (FunctionReference) argument;
                    final String functionName = candidate.getName();
                    if (functionName != null && functionName.equals("file_get_contents")) {
                        final PsiElement[] functionArguments = candidate.getParameters();
                        if (functionArguments.length == 1) {
                            mappingResult = functionArguments[0];
                        }
                    }
                }
                return mappingResult;
            }).collect(Collectors.toList());
            /* now check if reporting is needed */
            if (extracts.size() > 1) {
                final Function scope = ExpressionSemanticUtil.getScope(reference);
                final boolean shouldReport = scope == null || !scope.getName().equals("assertFileEquals");
                if (shouldReport) {
                    String[] suggestedArguments = null;
                    if (methodName.equals("assertStringEqualsFile") && extracts.get(1) != null) {
                        suggestedArguments = new String[assertionArguments.length];
                        suggestedArguments[0] = assertionArguments[0].getText();
                        suggestedArguments[1] = extracts.get(1).getText();
                        if (assertionArguments.length > 2) {
                            suggestedArguments[2] = assertionArguments[2].getText();
                        }
                    } else if (extracts.get(0) != null && extracts.get(1) != null) {
                        suggestedArguments = new String[assertionArguments.length];
                        suggestedArguments[0] = extracts.get(0).getText();
                        suggestedArguments[1] = extracts.get(1).getText();
                        if (assertionArguments.length > 2) {
                            suggestedArguments[2] = assertionArguments[2].getText();
                        }
                    }
                    if (suggestedArguments != null) {
                        final String suggestedAssertion = "assertFileEquals";
                        holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), suggestedAssertion), new PhpUnitAssertFixer(suggestedAssertion, suggestedArguments));
                        result = true;
                    }
                }
            }
            extracts.clear();
        }
    }
    return result;
}
Also used : Arrays(java.util.Arrays) ExpressionSemanticUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.ExpressionSemanticUtil) Function(com.jetbrains.php.lang.psi.elements.Function) Set(java.util.Set) MethodReference(com.jetbrains.php.lang.psi.elements.MethodReference) Collectors(java.util.stream.Collectors) HashSet(java.util.HashSet) OpenapiTypesUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.OpenapiTypesUtil) List(java.util.List) MessagesPresentationUtil(com.kalessil.phpStorm.phpInspectionsEA.utils.MessagesPresentationUtil) PsiElement(com.intellij.psi.PsiElement) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) NotNull(org.jetbrains.annotations.NotNull) PhpUnitAssertFixer(com.kalessil.phpStorm.phpInspectionsEA.fixers.PhpUnitAssertFixer) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) Function(com.jetbrains.php.lang.psi.elements.Function) PhpUnitAssertFixer(com.kalessil.phpStorm.phpInspectionsEA.fixers.PhpUnitAssertFixer) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) PsiElement(com.intellij.psi.PsiElement)

Example 32 with FunctionReference

use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.

the class IncorrectRandomRangeInspector 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.contains(functionName)) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 2) {
                    final Set<PsiElement> fromVariants = PossibleValuesDiscoveryUtil.discover(arguments[0]);
                    if (fromVariants.size() == 1) {
                        final PsiElement from = fromVariants.iterator().next();
                        if (OpenapiTypesUtil.isNumber(from)) {
                            final Set<PsiElement> toVariants = PossibleValuesDiscoveryUtil.discover(arguments[1]);
                            if (toVariants.size() == 1) {
                                final PsiElement to = toVariants.iterator().next();
                                if (OpenapiTypesUtil.isNumber(to)) {
                                    boolean isTarget;
                                    try {
                                        isTarget = Long.parseLong(to.getText()) < Long.parseLong(from.getText());
                                    } catch (final NumberFormatException wrongFormat) {
                                        isTarget = false;
                                    }
                                    if (isTarget) {
                                        holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(message));
                                    }
                                }
                            }
                            toVariants.clear();
                        }
                    }
                    fromVariants.clear();
                }
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) NotNull(org.jetbrains.annotations.NotNull) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 33 with FunctionReference

use of com.jetbrains.php.lang.psi.elements.FunctionReference 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;
        }
    };
}
Also used : UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) NotNull(org.jetbrains.annotations.NotNull) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) IElementType(com.intellij.psi.tree.IElementType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 34 with FunctionReference

use of com.jetbrains.php.lang.psi.elements.FunctionReference in project phpinspectionsea by kalessil.

the class UnserializeExploitsInspector 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("unserialize")) {
                final boolean supportsOptions = PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP700);
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 1 && !this.isTestContext(reference)) {
                    /* pattern: use 2nd argument since PHP7 */
                    if (supportsOptions) {
                        holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageUseSecondArgument));
                    }
                    /* pattern: exploitable calls */
                    this.inspectExploits(holder, arguments[0]);
                } else if (arguments.length == 2 && !this.isTestContext(reference)) {
                    if (arguments[1] instanceof ArrayCreationExpression) {
                        final boolean hasClassesListed = arguments[1].getChildren().length > 0;
                        if (!hasClassesListed) {
                            holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageUseSecondArgument));
                        }
                    } else if (PhpLanguageUtil.isTrue(arguments[1])) {
                        holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageUseSecondArgument));
                    }
                }
            }
        }

        private void inspectExploits(@NotNull ProblemsHolder holder, @NotNull PsiElement argument) {
            final Set<PsiElement> values = PossibleValuesDiscoveryUtil.discover(argument);
            if (!values.isEmpty()) {
                final List<String> reporting = new ArrayList<>();
                for (PsiElement value : values) {
                    if (OpenapiTypesUtil.isFunctionReference(value)) {
                        final FunctionReference call = (FunctionReference) value;
                        final String functionName = call.getName();
                        if (functionName != null && untrustedFunctions.contains(functionName)) {
                            reporting.add(functionName + "(...)");
                        }
                        continue;
                    }
                    /* extract array access variable */
                    if (value instanceof ArrayAccessExpression) {
                        PsiElement container = value;
                        while (container instanceof ArrayAccessExpression) {
                            container = ((ArrayAccessExpression) container).getValue();
                        }
                        if (container instanceof Variable) {
                            value = container;
                        }
                    }
                    if (value instanceof Variable && untrustedVars.contains(((Variable) value).getName())) {
                        reporting.add(value.getText());
                    // continue
                    }
                /* other expressions are not supported currently */
                }
                /* got something for reporting */
                if (!reporting.isEmpty()) {
                    /* sort reporting list to produce testable results */
                    Collections.sort(reporting);
                    holder.registerProblem(argument, MessagesPresentationUtil.prefixWithEa(messagePattern.replace("%e%", String.join(", ", reporting))), ProblemHighlightType.GENERIC_ERROR);
                    reporting.clear();
                }
            }
            values.clear();
        }
    };
}
Also used : Variable(com.jetbrains.php.lang.psi.elements.Variable) ArrayCreationExpression(com.jetbrains.php.lang.psi.elements.ArrayCreationExpression) NotNull(org.jetbrains.annotations.NotNull) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 35 with FunctionReference

use of com.jetbrains.php.lang.psi.elements.FunctionReference 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());
        }
    }
}
Also used : IElementType(com.intellij.psi.tree.IElementType) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) MethodReference(com.jetbrains.php.lang.psi.elements.MethodReference) HashMap(java.util.HashMap) Map(java.util.Map) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType)

Aggregations

FunctionReference (com.jetbrains.php.lang.psi.elements.FunctionReference)58 PsiElement (com.intellij.psi.PsiElement)55 NotNull (org.jetbrains.annotations.NotNull)46 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)43 BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)16 StringLiteralExpression (com.jetbrains.php.lang.psi.elements.StringLiteralExpression)15 IElementType (com.intellij.psi.tree.IElementType)11 PhpUnitAssertFixer (com.kalessil.phpStorm.phpInspectionsEA.fixers.PhpUnitAssertFixer)9 ArrayCreationExpression (com.jetbrains.php.lang.psi.elements.ArrayCreationExpression)6 UnaryExpression (com.jetbrains.php.lang.psi.elements.UnaryExpression)6 Function (com.jetbrains.php.lang.psi.elements.Function)5 MethodReference (com.jetbrains.php.lang.psi.elements.MethodReference)5 ParameterList (com.jetbrains.php.lang.psi.elements.ParameterList)5 PhpLanguageLevel (com.jetbrains.php.config.PhpLanguageLevel)4 ArrayList (java.util.ArrayList)4 Nullable (org.jetbrains.annotations.Nullable)4 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)3 PsiWhiteSpace (com.intellij.psi.PsiWhiteSpace)3 ArrayAccessExpression (com.jetbrains.php.lang.psi.elements.ArrayAccessExpression)3 HashSet (java.util.HashSet)3