Search in sources :

Example 1 with ArrayAccessExpression

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

the class ArrayPushMissUseInspector 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("array_push")) {
                final PsiElement[] arguments = reference.getParameters();
                if (arguments.length == 2 && OpenapiTypesUtil.isStatementImpl(reference.getParent())) {
                    PsiElement variadicCandidate = arguments[1].getPrevSibling();
                    if (variadicCandidate instanceof PsiWhiteSpace) {
                        variadicCandidate = variadicCandidate.getPrevSibling();
                    }
                    if (!OpenapiTypesUtil.is(variadicCandidate, PhpTokenTypes.opVARIADIC)) {
                        final String replacement = String.format("%s[] = %s", arguments[0].getText(), arguments[1].getText());
                        holder.registerProblem(reference, String.format(MessagesPresentationUtil.prefixWithEa(messageMisuse), replacement), new UseElementPushFix(replacement));
                    }
                }
            }
        }

        @Override
        public void visitPhpArrayAccessExpression(@NotNull ArrayAccessExpression expression) {
            if (REPORT_EXCESSIVE_COUNT_CALLS) {
                final PsiElement parent = expression.getParent();
                if (OpenapiTypesUtil.isAssignment(parent)) {
                    final PsiElement value = ((AssignmentExpression) parent).getValue();
                    if (value != expression) {
                        final ArrayIndex index = expression.getIndex();
                        if (index != null) {
                            final PsiElement candidate = index.getValue();
                            if (OpenapiTypesUtil.isFunctionReference(candidate)) {
                                final FunctionReference reference = (FunctionReference) candidate;
                                final String functionName = reference.getName();
                                if (functionName != null && functionName.equals("count")) {
                                    final PsiElement[] arguments = reference.getParameters();
                                    if (arguments.length == 1) {
                                        final PsiElement container = expression.getValue();
                                        if (container != null && OpenapiEquivalenceUtil.areEqual(container, arguments[0])) {
                                            holder.registerProblem(reference, MessagesPresentationUtil.prefixWithEa(messageUnneeded), ProblemHighlightType.LIKE_UNUSED_SYMBOL);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) AssignmentExpression(com.jetbrains.php.lang.psi.elements.AssignmentExpression) FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) NotNull(org.jetbrains.annotations.NotNull) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) ArrayIndex(com.jetbrains.php.lang.psi.elements.ArrayIndex) PsiElement(com.intellij.psi.PsiElement) PsiWhiteSpace(com.intellij.psi.PsiWhiteSpace) NotNull(org.jetbrains.annotations.NotNull)

Example 2 with ArrayAccessExpression

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

the class UnnecessaryIssetArgumentsInspector method buildVisitor.

@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
    return new BasePhpElementVisitor() {

        @Override
        public void visitPhpIsset(@NotNull PhpIsset issetExpression) {
            final PsiElement[] arguments = issetExpression.getVariables();
            if (arguments.length > 1) {
                final Set<PsiElement> reported = new HashSet<>();
                for (final PsiElement current : arguments) {
                    if (current instanceof ArrayAccessExpression && !reported.contains(current)) {
                        /* collect current element bases */
                        final List<PsiElement> bases = new ArrayList<>();
                        PsiElement base = current;
                        while (base instanceof ArrayAccessExpression) {
                            base = ((ArrayAccessExpression) base).getValue();
                            if (base != null) {
                                bases.add(base);
                            }
                        }
                        /* iterate arguments once more to match */
                        if (!bases.isEmpty()) {
                            for (final PsiElement discoveredBase : bases) {
                                for (final PsiElement match : arguments) {
                                    if (match != current && !reported.contains(match) && OpenapiEquivalenceUtil.areEqual(discoveredBase, match)) {
                                        holder.registerProblem(match, MessagesPresentationUtil.prefixWithEa(message), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new DropArgumentFix());
                                        reported.add(match);
                                    }
                                }
                            }
                            bases.clear();
                        }
                    }
                }
                reported.clear();
            }
        }
    };
}
Also used : BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) ArrayList(java.util.ArrayList) NotNull(org.jetbrains.annotations.NotNull) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) PsiElement(com.intellij.psi.PsiElement) PhpIsset(com.jetbrains.php.lang.psi.elements.PhpIsset) HashSet(java.util.HashSet) NotNull(org.jetbrains.annotations.NotNull)

Example 3 with ArrayAccessExpression

use of com.jetbrains.php.lang.psi.elements.ArrayAccessExpression 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();
                        }
                    }
                }
            }
        }
    };
}
Also used : java.util(java.util) BasePhpInspection(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpInspection) IElementType(com.intellij.psi.tree.IElementType) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) AssignmentExpression(com.jetbrains.php.lang.psi.elements.AssignmentExpression) PhpTokenTypes(com.jetbrains.php.lang.lexer.PhpTokenTypes) UseSuggestedReplacementFixer(com.kalessil.phpStorm.phpInspectionsEA.fixers.UseSuggestedReplacementFixer) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) Collectors(java.util.stream.Collectors) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) com.kalessil.phpStorm.phpInspectionsEA.utils(com.kalessil.phpStorm.phpInspectionsEA.utils) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) PsiElement(com.intellij.psi.PsiElement) PhpType(com.jetbrains.php.lang.psi.resolve.types.PhpType) NotNull(org.jetbrains.annotations.NotNull) PsiElementVisitor(com.intellij.psi.PsiElementVisitor) ProblemsHolder(com.intellij.codeInspection.ProblemsHolder) 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) AssignmentExpression(com.jetbrains.php.lang.psi.elements.AssignmentExpression) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) PhpTypedElement(com.jetbrains.php.lang.psi.elements.PhpTypedElement) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) PsiElement(com.intellij.psi.PsiElement) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with ArrayAccessExpression

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

the class GenerateAlternativeFromArrayKeyExistsStrategy method generate.

@Nullable
public static String generate(@NotNull TernaryExpression expression) {
    /* handle inverted cases */
    PsiElement callCandidate = ExpressionSemanticUtil.getExpressionTroughParenthesis(expression.getCondition());
    boolean isInverted = false;
    if (callCandidate instanceof UnaryExpression) {
        final PsiElement operator = ((UnaryExpression) callCandidate).getOperation();
        if (null != operator && PhpTokenTypes.opNOT == operator.getNode().getElementType()) {
            isInverted = true;
            callCandidate = ((UnaryExpression) callCandidate).getValue();
        }
    }
    /* verify condition structure */
    final FunctionReference call = OpenapiTypesUtil.isFunctionReference(callCandidate) ? (FunctionReference) callCandidate : null;
    final String functionName = null == call ? null : call.getName();
    if (null == functionName || 2 != call.getParameters().length || !functionName.equals("array_key_exists")) {
        return null;
    }
    /* array_key_exists is valid only with null-alternatives */
    final PsiElement alternative = ExpressionSemanticUtil.getExpressionTroughParenthesis(isInverted ? expression.getTrueVariant() : expression.getFalseVariant());
    final PsiElement value = ExpressionSemanticUtil.getExpressionTroughParenthesis(isInverted ? expression.getFalseVariant() : expression.getTrueVariant());
    if (!(value instanceof ArrayAccessExpression) || !PhpLanguageUtil.isNull(alternative)) {
        return null;
    }
    /* verify condition and variant structure */
    final PsiElement[] params = call.getParameters();
    final ArrayAccessExpression array = (ArrayAccessExpression) value;
    final PsiElement container = array.getValue();
    final PsiElement index = null == array.getIndex() ? null : array.getIndex().getValue();
    if (null == params[0] || null == params[1] || null == container || null == index) {
        return null;
    }
    if (!OpenapiEquivalenceUtil.areEqual(params[1], container) || !OpenapiEquivalenceUtil.areEqual(params[0], index)) {
        return null;
    }
    return value.getText() + " ?? " + alternative.getText();
}
Also used : FunctionReference(com.jetbrains.php.lang.psi.elements.FunctionReference) UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) ArrayAccessExpression(com.jetbrains.php.lang.psi.elements.ArrayAccessExpression) PsiElement(com.intellij.psi.PsiElement) Nullable(org.jetbrains.annotations.Nullable)

Example 5 with ArrayAccessExpression

use of com.jetbrains.php.lang.psi.elements.ArrayAccessExpression 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)

Aggregations

PsiElement (com.intellij.psi.PsiElement)5 ArrayAccessExpression (com.jetbrains.php.lang.psi.elements.ArrayAccessExpression)5 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)4 NotNull (org.jetbrains.annotations.NotNull)4 FunctionReference (com.jetbrains.php.lang.psi.elements.FunctionReference)3 ProblemsHolder (com.intellij.codeInspection.ProblemsHolder)2 AssignmentExpression (com.jetbrains.php.lang.psi.elements.AssignmentExpression)2 PsiElementVisitor (com.intellij.psi.PsiElementVisitor)1 PsiWhiteSpace (com.intellij.psi.PsiWhiteSpace)1 IElementType (com.intellij.psi.tree.IElementType)1 PhpTokenTypes (com.jetbrains.php.lang.lexer.PhpTokenTypes)1 ArrayCreationExpression (com.jetbrains.php.lang.psi.elements.ArrayCreationExpression)1 ArrayIndex (com.jetbrains.php.lang.psi.elements.ArrayIndex)1 BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)1 PhpIsset (com.jetbrains.php.lang.psi.elements.PhpIsset)1 PhpTypedElement (com.jetbrains.php.lang.psi.elements.PhpTypedElement)1 UnaryExpression (com.jetbrains.php.lang.psi.elements.UnaryExpression)1 Variable (com.jetbrains.php.lang.psi.elements.Variable)1 PhpType (com.jetbrains.php.lang.psi.resolve.types.PhpType)1 UseSuggestedReplacementFixer (com.kalessil.phpStorm.phpInspectionsEA.fixers.UseSuggestedReplacementFixer)1