Search in sources :

Example 1 with PhpIsset

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

the class IssetAndNullComparisonStrategy method apply.

public static boolean apply(@NotNull List<PsiElement> conditions, @NotNull ProblemsHolder holder) {
    /* first ensure that we have null identity checks at all */
    final Map<PsiElement, PsiElement> nullTestSubjects = new HashMap<>();
    for (final PsiElement oneCondition : conditions) {
        if (oneCondition instanceof BinaryExpression) {
            final BinaryExpression expression = (BinaryExpression) oneCondition;
            /* we need only !== and === operations */
            final IElementType operator = expression.getOperationType();
            if (operator != PhpTokenTypes.opIDENTICAL && operator != PhpTokenTypes.opNOT_IDENTICAL) {
                continue;
            }
            /* quickly check if any operands is a constant */
            final PsiElement left = expression.getLeftOperand();
            final PsiElement right = expression.getRightOperand();
            if (!(left instanceof ConstantReference) && !(right instanceof ConstantReference)) {
                continue;
            }
            /* store null test subjects */
            if (PhpLanguageUtil.isNull(right)) {
                if (null != left) {
                    nullTestSubjects.put(expression, left);
                }
                continue;
            }
            if (PhpLanguageUtil.isNull(left)) {
                if (null != right) {
                    nullTestSubjects.put(expression, right);
                }
            // continue;
            }
        }
    }
    if (0 == nullTestSubjects.size()) {
        return false;
    }
    boolean hasReportedExpressions = false;
    for (final PsiElement oneCondition : conditions) {
        /* do not process null identity checks */
        if (nullTestSubjects.containsKey(oneCondition)) {
            continue;
        }
        /* unwrap ! and () */
        PsiElement issetCandidate = oneCondition;
        if (issetCandidate instanceof UnaryExpression) {
            final PsiElement notOperatorCandidate = ((UnaryExpression) issetCandidate).getOperation();
            if (null != notOperatorCandidate && notOperatorCandidate.getNode().getElementType() == PhpTokenTypes.opNOT) {
                PsiElement invertedValue = ((UnaryExpression) issetCandidate).getValue();
                invertedValue = ExpressionSemanticUtil.getExpressionTroughParenthesis(invertedValue);
                if (null == invertedValue) {
                    continue;
                }
                issetCandidate = invertedValue;
            }
        }
        if (!(issetCandidate instanceof PhpIsset) || 0 == ((PhpIsset) issetCandidate).getVariables().length) {
            continue;
        }
        /* process isset constructions */
        for (final PsiElement issetArgument : ((PhpIsset) issetCandidate).getVariables()) {
            /* compare with know null identity checked subjects */
            for (final Map.Entry<PsiElement, PsiElement> nullTestPair : nullTestSubjects.entrySet()) {
                if (!OpeanapiEquivalenceUtil.areEqual(nullTestPair.getValue(), issetArgument)) {
                    continue;
                }
                hasReportedExpressions = true;
                final PsiElement nullTestExpression = nullTestPair.getKey();
                final String message = messagePattern.replace("%e%", nullTestExpression.getText());
                holder.registerProblem(nullTestExpression, message, ProblemHighlightType.WEAK_WARNING);
            }
        }
    }
    nullTestSubjects.clear();
    return hasReportedExpressions;
}
Also used : IElementType(com.intellij.psi.tree.IElementType) ConstantReference(com.jetbrains.php.lang.psi.elements.ConstantReference) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) HashMap(java.util.HashMap) UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) HashMap(java.util.HashMap) Map(java.util.Map) PsiElement(com.intellij.psi.PsiElement) PhpIsset(com.jetbrains.php.lang.psi.elements.PhpIsset)

Example 2 with PhpIsset

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

the class NotEmptyCanBeUsedStrategy method apply.

public static boolean apply(@NotNull List<PsiElement> conditions, @Nullable IElementType operation, @NotNull ProblemsHolder holder) {
    boolean result = false;
    if (conditions.size() > 1 && PhpTokenTypes.tsSHORT_CIRCUIT_AND_OPS.contains(operation)) {
        for (final PsiElement issetCandidate : conditions) {
            if (issetCandidate instanceof PhpIsset) {
                final PhpIsset isset = (PhpIsset) issetCandidate;
                final PsiElement[] arguments = isset.getVariables();
                for (final PsiElement argument : arguments) {
                    final Class clazz = argument.getClass();
                    for (final PsiElement match : conditions) {
                        if (match == issetCandidate || match.getClass() != clazz) {
                            continue;
                        }
                        if (OpeanapiEquivalenceUtil.areEqual(argument, match)) {
                            result = true;
                            final String argumentAsText = argument.getText();
                            final String message = String.format(messagePattern, argumentAsText, argumentAsText, argumentAsText);
                            final PsiElement target = arguments.length == 1 ? isset : argument;
                            holder.registerProblem(target, message, ProblemHighlightType.WEAK_WARNING);
                            break;
                        }
                    }
                }
            }
        }
    }
    return result;
}
Also used : PsiElement(com.intellij.psi.PsiElement) PhpIsset(com.jetbrains.php.lang.psi.elements.PhpIsset)

Example 3 with PhpIsset

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

the class IssetConstructsCanBeMergedInspector method buildVisitor.

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

        @Override
        public void visitPhpBinaryExpression(@NotNull BinaryExpression expression) {
            final IElementType operator = expression.getOperationType();
            if (operator != null && (operator == PhpTokenTypes.opAND || operator == PhpTokenTypes.opOR)) {
                /* false-positives: part of another condition */
                final PsiElement parent = expression.getParent();
                final PsiElement context = parent instanceof ParenthesizedExpression ? parent.getParent() : parent;
                if (context instanceof BinaryExpression && ((BinaryExpression) context).getOperationType() == operator) {
                    return;
                }
                final List<PsiElement> fragments = this.extract(expression, operator);
                if (fragments.size() > 1) {
                    if (operator == PhpTokenTypes.opAND) {
                        /* handle isset && isset ... */
                        PsiElement firstHit = null;
                        int hitsCount = 0;
                        for (final PsiElement fragment : fragments) {
                            if (fragment instanceof PhpIsset) {
                                if (++hitsCount > 1 && firstHit != null) {
                                    fragments.remove(firstHit);
                                    fragments.remove(fragment);
                                    holder.registerProblem(fragment, MessagesPresentationUtil.prefixWithEa(messageIsset), new MergeConstructsFix(holder.getProject(), expression, fragments, (PhpIsset) firstHit, (PhpIsset) fragment, operator));
                                    break;
                                }
                                firstHit = firstHit == null ? fragment : firstHit;
                            }
                        }
                    } else {
                        /* handle !isset || !isset ... */
                        PsiElement firstHit = null;
                        int hitsCount = 0;
                        for (final PsiElement fragment : fragments) {
                            if (fragment instanceof UnaryExpression) {
                                final PsiElement candidate = ((UnaryExpression) fragment).getValue();
                                if (candidate instanceof PhpIsset) {
                                    if (++hitsCount > 1 && firstHit != null) {
                                        fragments.remove(firstHit.getParent());
                                        fragments.remove(fragment);
                                        holder.registerProblem(candidate, MessagesPresentationUtil.prefixWithEa(messageIvertedIsset), new MergeConstructsFix(holder.getProject(), expression, fragments, (PhpIsset) firstHit, (PhpIsset) candidate, operator));
                                        break;
                                    }
                                    firstHit = firstHit == null ? candidate : firstHit;
                                }
                            }
                        }
                    }
                }
                fragments.clear();
            }
        }

        @NotNull
        private List<PsiElement> extract(@NotNull BinaryExpression binary, @Nullable IElementType operator) {
            final List<PsiElement> result = new ArrayList<>();
            if (binary.getOperationType() == operator) {
                Stream.of(binary.getLeftOperand(), binary.getRightOperand()).filter(Objects::nonNull).map(ExpressionSemanticUtil::getExpressionTroughParenthesis).forEach(expression -> {
                    if (expression instanceof BinaryExpression) {
                        result.addAll(this.extract((BinaryExpression) expression, operator));
                    } else {
                        result.add(expression);
                    }
                });
            } else {
                result.add(binary);
            }
            return result;
        }
    };
}
Also used : ParenthesizedExpression(com.jetbrains.php.lang.psi.elements.ParenthesizedExpression) ArrayList(java.util.ArrayList) UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) NotNull(org.jetbrains.annotations.NotNull) IElementType(com.intellij.psi.tree.IElementType) BasePhpElementVisitor(com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor) BinaryExpression(com.jetbrains.php.lang.psi.elements.BinaryExpression) Objects(java.util.Objects) PsiElement(com.intellij.psi.PsiElement) Nullable(org.jetbrains.annotations.Nullable) PhpIsset(com.jetbrains.php.lang.psi.elements.PhpIsset) NotNull(org.jetbrains.annotations.NotNull)

Example 4 with PhpIsset

use of com.jetbrains.php.lang.psi.elements.PhpIsset 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 5 with PhpIsset

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

the class GenerateAlternativeFromIssetStrategy method generate.

@Nullable
public static String generate(@NotNull TernaryExpression expression) {
    /* handle inverted cases */
    PsiElement issetCandidate = ExpressionSemanticUtil.getExpressionTroughParenthesis(expression.getCondition());
    boolean isInverted = false;
    if (issetCandidate instanceof UnaryExpression) {
        final PsiElement operator = ((UnaryExpression) issetCandidate).getOperation();
        if (null != operator && PhpTokenTypes.opNOT == operator.getNode().getElementType()) {
            isInverted = true;
            issetCandidate = ((UnaryExpression) issetCandidate).getValue();
        }
    }
    /* verify condition structure */
    final PhpIsset isset = issetCandidate instanceof PhpIsset ? (PhpIsset) issetCandidate : null;
    if (null == isset || 1 != isset.getVariables().length) {
        return null;
    }
    /* verify subject match and alternative availability */
    final PsiElement subject = ExpressionSemanticUtil.getExpressionTroughParenthesis(isset.getVariables()[0]);
    final PsiElement value = ExpressionSemanticUtil.getExpressionTroughParenthesis(isInverted ? expression.getFalseVariant() : expression.getTrueVariant());
    final PsiElement alternative = ExpressionSemanticUtil.getExpressionTroughParenthesis(isInverted ? expression.getTrueVariant() : expression.getFalseVariant());
    if (null == subject || null == value || null == alternative || !OpenapiEquivalenceUtil.areEqual(subject, value)) {
        return null;
    }
    return subject.getText() + " ?? " + alternative.getText();
}
Also used : UnaryExpression(com.jetbrains.php.lang.psi.elements.UnaryExpression) PsiElement(com.intellij.psi.PsiElement) PhpIsset(com.jetbrains.php.lang.psi.elements.PhpIsset) Nullable(org.jetbrains.annotations.Nullable)

Aggregations

PsiElement (com.intellij.psi.PsiElement)5 PhpIsset (com.jetbrains.php.lang.psi.elements.PhpIsset)5 UnaryExpression (com.jetbrains.php.lang.psi.elements.UnaryExpression)3 IElementType (com.intellij.psi.tree.IElementType)2 BinaryExpression (com.jetbrains.php.lang.psi.elements.BinaryExpression)2 BasePhpElementVisitor (com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor)2 ArrayList (java.util.ArrayList)2 NotNull (org.jetbrains.annotations.NotNull)2 Nullable (org.jetbrains.annotations.Nullable)2 ArrayAccessExpression (com.jetbrains.php.lang.psi.elements.ArrayAccessExpression)1 ConstantReference (com.jetbrains.php.lang.psi.elements.ConstantReference)1 ParenthesizedExpression (com.jetbrains.php.lang.psi.elements.ParenthesizedExpression)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Objects (java.util.Objects)1