use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class NotOptimalRegularExpressionsInspector 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[] params = reference.getParameters();
if (params.length > 0) {
final boolean checkCall = !(params[0] instanceof ArrayCreationExpression);
final Set<StringLiteralExpression> patterns = this.extractPatterns(params[0]);
for (final StringLiteralExpression pattern : patterns) {
if (pattern.getContainingFile() == params[0].getContainingFile()) {
final String regex = pattern.getContents();
if (!regex.isEmpty() && pattern.getFirstPsiChild() == null) {
boolean hasDelimiters = false;
for (final Pattern matchPattern : matchers) {
final Matcher matcher = matchPattern.matcher(regex);
if (hasDelimiters = matcher.find()) {
final String phpRegexPattern = matcher.group(2);
final String phpRegexModifiers = matcher.group(4);
this.checkRegex(functionName, reference, pattern, phpRegexPattern, phpRegexModifiers);
if (checkCall) {
this.checkCall(functionName, reference, phpRegexPattern, phpRegexModifiers);
}
break;
}
}
if (!hasDelimiters && !functionName.equals("preg_quote")) {
holder.registerProblem(pattern, MessagesPresentationUtil.prefixWithEa(messageNoDelimiters));
}
}
}
patterns.clear();
}
}
}
}
private Set<StringLiteralExpression> extractPatterns(@NotNull PsiElement candidate) {
final Set<StringLiteralExpression> result = new HashSet<>();
if (candidate instanceof ArrayCreationExpression) {
for (final PsiElement child : candidate.getChildren()) {
/* extract element */
final StringLiteralExpression element;
if (child instanceof ArrayHashElement) {
element = ExpressionSemanticUtil.resolveAsStringLiteral(((ArrayHashElement) child).getValue());
} else if (child instanceof PhpPsiElement) {
element = ExpressionSemanticUtil.resolveAsStringLiteral(child);
} else {
element = null;
}
/* resolve element */
if (element != null) {
result.add(element);
}
}
} else {
final StringLiteralExpression literal = ExpressionSemanticUtil.resolveAsStringLiteral(candidate);
if (literal != null) {
result.add(literal);
}
}
return result;
}
private void checkRegex(String functionName, FunctionReference reference, StringLiteralExpression target, String regex, String modifiers) {
/* Modifiers validity (done):
* + /no-az-chars/i => /no-az-chars/
* + /no-dot-char/s => /no-dot-char/
* + /no-$/D => /no-$/
* + /no-^-or-$-occurrences/m => /no-^-or-$-occurrences/
* + /regexp/e => mark as deprecated, use preg_replace_callback instead
* + Check allowed PHP modifiers: eimsuxADJSUX
*/
DeprecatedModifiersCheckStrategy.apply(modifiers, target, holder);
AllowedModifierCheckStrategy.apply(functionName, modifiers, target, holder);
UselessDollarEndOnlyModifierStrategy.apply(modifiers, regex, target, holder);
UselessDotAllModifierCheckStrategy.apply(modifiers, regex, target, holder);
UselessIgnoreCaseModifierCheckStrategy.apply(modifiers, regex, target, holder);
/* Classes shortening (done):
* + [0-9] => \d
* + [^0-9] => \D
* + [:digit:] => \d
* + [:word:] => \w
* + [^\w] => \W
* + [^\s] => \S
*/
ShortClassDefinitionStrategy.apply(modifiers, regex, target, holder);
/* Optimizations:
* (...) => (?:...) (if there is no back-reference)
*
* + .*?[symbol] at the end of regexp => [^symbol]*[symbol] (e.g. xml/html parsing using <.*?> vs <[^>]*>)
* + .+?[symbol] at the end of regexp => [^symbol]+[symbol]
* + / .* ··· /, / ···.* / => /···/ (remove leading and trailing .* without ^ or $, note: if no back-reference to \0)
* + [seq][seq]... => [seq]{N}
* + [seq][seq]+ => [seq]{2,}
* + [seq][seq]* => [seq]+
* + [seq][seq]? => [seq]{1,2}
*
* + greedy character classes [\d\w][\D\W]
* + dangerous (a+)+ pattern
*/
SequentialClassesCollapseCheckStrategy.apply(regex, target, holder);
AmbiguousAnythingTrimCheckStrategy.apply(functionName, reference, regex, target, holder);
GreedyCharactersSetCheckStrategy.apply(regex, target, holder);
QuantifierCompoundsQuantifierCheckStrategy.apply(regex, target, holder);
/*
* Probably bugs:
* - nested tags check without /s
* - unicode characters without /u
*/
MissingDotAllCheckStrategy.apply(modifiers, regex, target, holder);
MissingUnicodeModifierStrategy.apply(functionName, modifiers, regex, target, holder);
}
private void checkCall(String functionName, FunctionReference reference, String regex, String modifiers) {
/* Plain API simplification (done):
* + /^text/ => 0 === strpos(...) (match)
* + /text/ => false !== strpos(...) (match) / str_replace (replace)
* + /^text/i => 0 === stripos(...) (match)
* + /text/i => false !== stripos(...) (match) / str_ireplace (replace)
* + preg_quote => warning if second argument is not presented
* + preg_match_all without match argument preg_match
*/
FunctionCallCheckStrategy.apply(functionName, reference, holder);
PlainApiUseCheckStrategy.apply(functionName, reference, modifiers, regex, holder);
/* source checks */
UnnecessaryCaseManipulationCheckStrategy.apply(functionName, reference, modifiers, holder);
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class NullCoalescingOperatorCanBeUsedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpTernaryExpression(@NotNull TernaryExpression expression) {
if (SUGGEST_SIMPLIFYING_TERNARIES && !expression.isShort() && PhpLanguageLevel.get(holder.getProject()).atLeast(PhpLanguageLevel.PHP700)) {
final PsiElement condition = ExpressionSemanticUtil.getExpressionTroughParenthesis(expression.getCondition());
if (condition != null) {
final PsiElement extracted = this.getTargetCondition(condition);
if (extracted != null) {
final PsiElement firstValue = expression.getTrueVariant();
final PsiElement secondValue = expression.getFalseVariant();
if (firstValue != null && secondValue != null) {
final String replacement = this.generateReplacement(condition, extracted, firstValue, secondValue);
if (replacement != null) {
holder.registerProblem(expression, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new ReplaceSingleConstructFix(replacement));
}
}
}
}
}
}
@Override
public void visitPhpIf(@NotNull If statement) {
final Project project = holder.getProject();
if (SUGGEST_SIMPLIFYING_IFS && PhpLanguageLevel.get(project).atLeast(PhpLanguageLevel.PHP700)) {
final PsiElement condition = ExpressionSemanticUtil.getExpressionTroughParenthesis(statement.getCondition());
if (condition != null && statement.getElseIfBranches().length == 0) {
final PsiElement extracted = this.getTargetCondition(condition);
if (extracted != null) {
final Couple<Couple<PsiElement>> fragments = this.extract(statement);
final PsiElement firstValue = fragments.second.first;
final PsiElement secondValue = fragments.second.second;
if (firstValue != null) {
final String coalescing = this.generateReplacement(condition, extracted, firstValue, secondValue);
if (coalescing != null) {
final PsiElement context = firstValue.getParent();
if (context instanceof PhpReturn) {
final String replacement = String.format("return %s", coalescing);
holder.registerProblem(statement.getFirstChild(), String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new ReplaceMultipleConstructFix(project, fragments.first.first, fragments.first.second, replacement));
} else if (context instanceof AssignmentExpression) {
final PsiElement container = ((AssignmentExpression) context).getVariable();
final String replacement = String.format("%s = %s", container.getText(), coalescing);
holder.registerProblem(statement.getFirstChild(), String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new ReplaceMultipleConstructFix(project, fragments.first.first, fragments.first.second, replacement));
}
}
}
}
}
}
}
private boolean wrap(@Nullable PsiElement expression) {
if (expression instanceof TernaryExpression || expression instanceof AssignmentExpression) {
return true;
} else if (expression instanceof BinaryExpression) {
return ((BinaryExpression) expression).getOperationType() != PhpTokenTypes.opCOALESCE;
}
return false;
}
@Nullable
private String generateReplacement(@NotNull PsiElement condition, @NotNull PsiElement extracted, @NotNull PsiElement first, @Nullable PsiElement second) {
String coalescing = null;
if (extracted instanceof PhpIsset) {
coalescing = this.generateReplacementForIsset(condition, (PhpIsset) extracted, first, second);
} else if (extracted instanceof PhpEmpty) {
coalescing = this.generateReplacementForPropertyAccess(condition, (PhpEmpty) extracted, first, second);
} else if (extracted instanceof Variable || extracted instanceof ArrayAccessExpression || extracted instanceof FieldReference) {
coalescing = this.generateReplacementForPropertyAccess(condition, extracted, first, second);
} else if (extracted instanceof FunctionReference) {
if (second != null) {
coalescing = this.generateReplacementForExists(condition, (FunctionReference) extracted, first, second);
}
} else if (extracted instanceof BinaryExpression) {
if (second != null) {
coalescing = this.generateReplacementForIdentity(condition, (BinaryExpression) extracted, first, second);
}
}
return coalescing;
}
@Nullable
private String generateReplacementForExists(@NotNull PsiElement condition, @NotNull FunctionReference extracted, @NotNull PsiElement first, @NotNull PsiElement second) {
final PsiElement[] arguments = extracted.getParameters();
if (arguments.length == 2) {
final boolean expectsToBeSet = condition == extracted;
final PsiElement candidate = expectsToBeSet ? first : second;
final PsiElement alternative = expectsToBeSet ? second : first;
if (candidate instanceof ArrayAccessExpression && PhpLanguageUtil.isNull(alternative)) {
final ArrayAccessExpression access = (ArrayAccessExpression) candidate;
final PsiElement container = access.getValue();
if (container != null && OpenapiEquivalenceUtil.areEqual(container, arguments[1])) {
final ArrayIndex index = access.getIndex();
if (index != null) {
final PsiElement key = index.getValue();
if (key != null && OpenapiEquivalenceUtil.areEqual(key, arguments[0])) {
return String.format("%s ?? %s", String.format(this.wrap(candidate) ? "(%s)" : "%s", candidate.getText()), String.format(this.wrap(alternative) ? "(%s)" : "%s", alternative.getText()));
}
}
}
}
}
return null;
}
@Nullable
private String generateReplacementForIdentity(@NotNull PsiElement condition, @NotNull BinaryExpression extracted, @NotNull PsiElement first, @NotNull PsiElement second) {
PsiElement subject = extracted.getLeftOperand();
if (PhpLanguageUtil.isNull(subject)) {
subject = extracted.getRightOperand();
}
if (subject != null) {
final IElementType operator = extracted.getOperationType();
final boolean expectsToBeSet = (operator == PhpTokenTypes.opNOT_IDENTICAL && condition == extracted) || (operator == PhpTokenTypes.opIDENTICAL && condition != extracted);
final PsiElement candidate = expectsToBeSet ? first : second;
if (OpenapiEquivalenceUtil.areEqual(candidate, subject)) {
final PsiElement alternative = expectsToBeSet ? second : first;
return String.format("%s ?? %s", String.format(this.wrap(candidate) ? "(%s)" : "%s", candidate.getText()), String.format(this.wrap(alternative) ? "(%s)" : "%s", alternative.getText()));
}
}
return null;
}
@Nullable
private String generateReplacementForIsset(@NotNull PsiElement condition, @NotNull PhpIsset extracted, @NotNull PsiElement first, @Nullable PsiElement second) {
final PsiElement subject = extracted.getVariables()[0];
if (subject != null) {
final boolean expectsToBeSet = condition == extracted;
final PsiElement candidate = expectsToBeSet ? first : second;
if (candidate != null && OpenapiEquivalenceUtil.areEqual(candidate, subject)) {
final PsiElement alternative = expectsToBeSet ? second : first;
return String.format("%s ?? %s", String.format(this.wrap(candidate) ? "(%s)" : "%s", candidate.getText()), String.format(this.wrap(alternative) ? "(%s)" : "%s", alternative == null ? "null" : alternative.getText()));
}
}
return null;
}
@Nullable
private String generateReplacementForPropertyAccess(@NotNull PsiElement condition, @NotNull PsiElement extracted, @NotNull PsiElement first, @Nullable PsiElement second) {
final boolean expectsToBeNotEmpty = condition == extracted;
final PsiElement candidate = expectsToBeNotEmpty ? first : second;
if (candidate instanceof FieldReference) {
final FieldReference fieldReference = (FieldReference) candidate;
final PsiElement base = fieldReference.getClassReference();
if (base != null && OpenapiEquivalenceUtil.areEqual(extracted, base)) {
final PhpType resolved = OpenapiResolveUtil.resolveType(fieldReference, holder.getProject());
if (resolved != null && !resolved.filterUnknown().isEmpty()) {
final PsiElement alternative = expectsToBeNotEmpty ? second : first;
final boolean isNullable = resolved.filterUnknown().getTypes().stream().map(Types::getType).anyMatch(t -> t.equals(Types.strNull));
if (!isNullable || (alternative == null || PhpLanguageUtil.isNull(alternative))) {
return String.format("%s ?? %s", String.format(this.wrap(fieldReference) ? "(%s)" : "%s", fieldReference.getText()), String.format(this.wrap(alternative) ? "(%s)" : "%s", alternative == null ? "null" : alternative.getText()));
}
}
}
}
return null;
}
@Nullable
private String generateReplacementForPropertyAccess(@NotNull PsiElement condition, @NotNull PhpEmpty extracted, @NotNull PsiElement first, @Nullable PsiElement second) {
final PsiElement subject = extracted.getVariables()[0];
if (subject != null) {
final boolean expectsToBeNotEmpty = condition != extracted;
final PsiElement candidate = expectsToBeNotEmpty ? first : second;
if (candidate instanceof FieldReference) {
final PsiElement reference = ((FieldReference) candidate).getClassReference();
if (reference != null && OpenapiEquivalenceUtil.areEqual(subject, reference)) {
final PsiElement alternative = expectsToBeNotEmpty ? second : first;
return String.format("%s ?? %s", String.format(this.wrap(candidate) ? "(%s)" : "%s", candidate.getText()), String.format(this.wrap(alternative) ? "(%s)" : "%s", alternative == null ? "null" : alternative.getText()));
}
}
}
return null;
}
@Nullable
private PsiElement getTargetCondition(@NotNull PsiElement condition) {
/* un-wrap inverted conditions */
if (condition instanceof UnaryExpression) {
final UnaryExpression unary = (UnaryExpression) condition;
if (OpenapiTypesUtil.is(unary.getOperation(), PhpTokenTypes.opNOT)) {
condition = ExpressionSemanticUtil.getExpressionTroughParenthesis(unary.getValue());
}
}
/* do check */
if (condition instanceof Variable || condition instanceof ArrayAccessExpression || condition instanceof FieldReference) {
return condition;
} else if (condition instanceof PhpIsset) {
final PhpIsset isset = (PhpIsset) condition;
if (isset.getVariables().length == 1) {
return condition;
}
} else if (condition instanceof PhpEmpty) {
final PhpEmpty empty = (PhpEmpty) condition;
if (empty.getVariables().length == 1) {
return condition;
}
} else if (condition instanceof BinaryExpression) {
final BinaryExpression binary = (BinaryExpression) condition;
final IElementType operator = binary.getOperationType();
if (operator == PhpTokenTypes.opIDENTICAL || operator == PhpTokenTypes.opNOT_IDENTICAL) {
if (PhpLanguageUtil.isNull(binary.getRightOperand())) {
return condition;
} else if (PhpLanguageUtil.isNull(binary.getLeftOperand())) {
return condition;
}
}
} else if (OpenapiTypesUtil.isFunctionReference(condition)) {
final String functionName = ((FunctionReference) condition).getName();
if (functionName != null && functionName.equals("array_key_exists")) {
return condition;
}
}
return null;
}
/* first pair: what to drop, second positive and negative branching values */
private Couple<Couple<PsiElement>> extract(@NotNull If statement) {
Couple<Couple<PsiElement>> result = new Couple<>(new Couple<>(null, null), new Couple<>(null, null));
final GroupStatement ifBody = ExpressionSemanticUtil.getGroupStatement(statement);
if (ifBody != null && ExpressionSemanticUtil.countExpressionsInGroup(ifBody) == 1) {
final PsiElement ifLast = this.extractCandidate(ExpressionSemanticUtil.getLastStatement(ifBody));
if (ifLast != null) {
/* extract all related constructs */
final PsiElement ifNext = this.extractCandidate(statement.getNextPsiSibling());
final PsiElement ifPrevious = this.extractCandidate(statement.getPrevPsiSibling());
if (statement.getElseBranch() != null) {
PsiElement elseLast = null;
final GroupStatement elseBody = ExpressionSemanticUtil.getGroupStatement(statement.getElseBranch());
if (elseBody != null && ExpressionSemanticUtil.countExpressionsInGroup(elseBody) == 1) {
elseLast = this.extractCandidate(ExpressionSemanticUtil.getLastStatement(elseBody));
}
/* if - return - else - return */
if (ifLast instanceof PhpReturn && elseLast instanceof PhpReturn) {
result = new Couple<>(new Couple<>(statement, statement), new Couple<>(((PhpReturn) ifLast).getArgument(), ((PhpReturn) elseLast).getArgument()));
} else /* if - assign - else - assign */
if (ifLast instanceof AssignmentExpression && elseLast instanceof AssignmentExpression) {
final AssignmentExpression ifAssignment = (AssignmentExpression) ifLast;
final AssignmentExpression elseAssignment = (AssignmentExpression) elseLast;
final PsiElement ifContainer = ifAssignment.getVariable();
final PsiElement elseContainer = elseAssignment.getVariable();
if (ifContainer instanceof Variable && elseContainer instanceof Variable) {
final boolean isTarget = OpenapiEquivalenceUtil.areEqual(ifContainer, elseContainer);
if (isTarget) {
result = new Couple<>(new Couple<>(statement, statement), new Couple<>(ifAssignment.getValue(), elseAssignment.getValue()));
}
}
}
} else {
/* assign - if - assign */
if (ifPrevious instanceof AssignmentExpression && ifLast instanceof AssignmentExpression) {
final AssignmentExpression previousAssignment = (AssignmentExpression) ifPrevious;
final AssignmentExpression ifAssignment = (AssignmentExpression) ifLast;
final PsiElement previousContainer = previousAssignment.getVariable();
final PsiElement ifContainer = ifAssignment.getVariable();
if (previousContainer instanceof Variable && ifContainer instanceof Variable) {
final boolean isTarget = OpenapiEquivalenceUtil.areEqual(previousContainer, ifContainer);
/* false-positives: assignment by value */
if (isTarget && !OpenapiTypesUtil.isAssignmentByReference(previousAssignment)) {
final PsiElement previousValue = previousAssignment.getValue();
if (!(previousValue instanceof AssignmentExpression)) {
/* false-positives: assignment of processed container value */
final boolean isContainerProcessing = PsiTreeUtil.findChildrenOfType(previousValue, previousContainer.getClass()).stream().anyMatch(c -> OpenapiEquivalenceUtil.areEqual(c, previousContainer));
if (!isContainerProcessing) {
result = new Couple<>(new Couple<>(ifPrevious.getParent(), statement), new Couple<>(ifAssignment.getValue(), previousValue));
}
}
}
}
} else /* if - return - return */
if (ifLast instanceof PhpReturn && ifNext instanceof PhpReturn) {
result = new Couple<>(new Couple<>(statement, ifNext), new Couple<>(((PhpReturn) ifLast).getArgument(), ((PhpReturn) ifNext).getArgument()));
} else /* if - return - [end-of-function] */
if (ifLast instanceof PhpReturn && ifNext == null && statement.getNextPsiSibling() == null) {
final boolean isInFunction = statement.getParent().getParent() instanceof Function;
if (isInFunction) {
result = new Couple<>(new Couple<>(statement, statement), new Couple<>(((PhpReturn) ifLast).getArgument(), null));
}
}
}
}
}
return result;
}
@Nullable
private PsiElement extractCandidate(@Nullable PsiElement statement) {
if (statement instanceof PhpReturn) {
return statement;
} else if (OpenapiTypesUtil.isStatementImpl(statement)) {
final PsiElement possiblyAssignment = statement.getFirstChild();
if (OpenapiTypesUtil.isAssignment(possiblyAssignment)) {
final AssignmentExpression assignment = (AssignmentExpression) possiblyAssignment;
final PsiElement container = assignment.getVariable();
if (container instanceof Variable) {
return assignment;
}
}
}
return null;
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class MagicMethodsValidityInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpMethod(@NotNull Method method) {
final PhpClass clazz = method.getContainingClass();
final String methodName = method.getName();
final PsiElement nameNode = NamedElementUtil.getNameIdentifier(method);
if (clazz == null || nameNode == null || !methodName.startsWith("_") || method.isAbstract()) {
return;
}
switch(methodName) {
case "__construct":
CanNotBeStaticStrategy.apply(method, holder);
CanNotReturnTypeStrategy.apply(method, holder);
if (!this.isTestContext(clazz)) {
NormallyCallsParentMethodStrategy.apply(method, holder);
}
break;
case "__destruct":
case "__clone":
CanNotBeStaticStrategy.apply(method, holder);
CanNotReturnTypeStrategy.apply(method, holder);
CanNotTakeArgumentsStrategy.apply(method, holder);
NormallyCallsParentMethodStrategy.apply(method, holder);
break;
case "__get":
case "__isset":
case "__unset":
TakesExactAmountOfArgumentsStrategy.apply(1, method, holder);
CanNotBeStaticStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
CanNotTakeArgumentsByReferenceStrategy.apply(method, holder);
HasAlsoMethodStrategy.apply(method, "__set", holder);
break;
case "__set":
case "__call":
TakesExactAmountOfArgumentsStrategy.apply(2, method, holder);
CanNotBeStaticStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
CanNotTakeArgumentsByReferenceStrategy.apply(method, holder);
if (methodName.equals("__set")) {
HasAlsoMethodStrategy.apply(method, "__isset", holder);
HasAlsoMethodStrategy.apply(method, "__get", holder);
}
break;
case "__callStatic":
TakesExactAmountOfArgumentsStrategy.apply(2, method, holder);
MustBeStaticStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
CanNotTakeArgumentsByReferenceStrategy.apply(method, holder);
break;
case "__toString":
CanNotBeStaticStrategy.apply(method, holder);
CanNotTakeArgumentsStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
MustReturnSpecifiedTypeStrategy.apply(stringType, method, holder);
break;
case "__debugInfo":
CanNotBeStaticStrategy.apply(method, holder);
CanNotTakeArgumentsStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
MustReturnSpecifiedTypeStrategy.apply(arrayOrNullType, method, holder);
MinimalPhpVersionStrategy.apply(method, holder, PhpLanguageLevel.PHP560);
break;
case "__set_state":
TakesExactAmountOfArgumentsStrategy.apply(1, method, holder);
MustBeStaticStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
final PhpType returnTypes = (new PhpType()).add(clazz.getFQN()).add(Types.strStatic);
MustReturnSpecifiedTypeStrategy.apply(returnTypes, method, holder);
break;
case "__invoke":
CanNotBeStaticStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
break;
case "__wakeup":
CanNotBeStaticStrategy.apply(method, holder);
CanNotTakeArgumentsStrategy.apply(method, holder);
CanNotReturnTypeStrategy.apply(method, holder);
break;
case "__unserialize":
CanNotBeStaticStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
TakesExactAmountOfArgumentsStrategy.apply(1, method, holder);
CanNotReturnTypeStrategy.apply(method, holder);
break;
case "__sleep":
case "__serialize":
CanNotBeStaticStrategy.apply(method, holder);
MustBePublicStrategy.apply(method, holder);
CanNotTakeArgumentsStrategy.apply(method, holder);
MustReturnSpecifiedTypeStrategy.apply(arrayType, method, holder);
break;
case "__autoload":
TakesExactAmountOfArgumentsStrategy.apply(1, method, holder);
CanNotReturnTypeStrategy.apply(method, holder);
holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageUseSplAutoloading), ProblemHighlightType.LIKE_DEPRECATED);
break;
default:
if (methodName.startsWith("__") && !knownNonMagic.contains(methodName)) {
holder.registerProblem(nameNode, MessagesPresentationUtil.prefixWithEa(messageNotMagic));
} else {
MissingUnderscoreStrategy.apply(method, holder);
}
break;
}
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor 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;
}
};
}
use of com.kalessil.phpStorm.phpInspectionsEA.openApi.BasePhpElementVisitor in project phpinspectionsea by kalessil.
the class RedundantElseClauseInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpIf(@NotNull If expression) {
/* context expectations: not if-else-if-* constructs */
if (expression.getParent() instanceof Else) {
return;
}
/* general construct expectations: body wrapped into {} and has alternative branches */
final GroupStatement ifBody = ExpressionSemanticUtil.getGroupStatement(expression);
if (ifBody == null || !ExpressionSemanticUtil.hasAlternativeBranches(expression)) {
return;
}
if (!OpenapiTypesUtil.is(ifBody.getFirstChild(), PhpTokenTypes.chLBRACE)) {
return;
}
/* collect alternative branches for reporting and QF binding */
final List<PhpPsiElement> alternativeBranches = new ArrayList<>(Arrays.asList(expression.getElseIfBranches()));
final Else elseBranch = expression.getElseBranch();
if (elseBranch != null) {
alternativeBranches.add(elseBranch);
}
/* alternative branch expectations */
final PhpPsiElement alternative = alternativeBranches.get(0);
final GroupStatement alternativeBody = ExpressionSemanticUtil.getGroupStatement(alternative);
if (alternative instanceof ElseIf && alternativeBody == null) {
alternativeBranches.clear();
return;
}
if (alternative instanceof Else && alternativeBody == null && !(alternative.getFirstPsiChild() instanceof If)) {
alternativeBranches.clear();
return;
}
/* analyze last statement in if and report if matched inspection pattern */
final PsiElement lastStatement = ExpressionSemanticUtil.getLastStatement(ifBody);
if (lastStatement != null) {
final boolean isExitStatement = lastStatement.getFirstChild() instanceof PhpExit;
final boolean isReturnPoint = isExitStatement || lastStatement instanceof PhpReturn || lastStatement instanceof PhpContinue || lastStatement instanceof PhpBreak || OpenapiTypesUtil.isThrowExpression(lastStatement);
if (isReturnPoint) {
holder.registerProblem(alternative.getFirstChild(), MessagesPresentationUtil.prefixWithEa(alternative instanceof Else ? messageElse : messageElseif), new UnnecessaryElseFixer());
}
}
alternativeBranches.clear();
}
};
}
Aggregations