use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class UnnecessaryCastingInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpUnaryExpression(@NotNull UnaryExpression expression) {
final PsiElement argument = ExpressionSemanticUtil.getExpressionTroughParenthesis(expression.getValue());
final PsiElement operation = expression.getOperation();
final IElementType operator = operation == null ? null : operation.getNode().getElementType();
if (operator != null && argument instanceof PhpTypedElement) {
final PsiElement parent = expression.getParent();
if (operator == PhpTokenTypes.opSTRING_CAST) {
/* case 1: concatenation `... . (string)...` */
if (parent instanceof BinaryExpression) {
final BinaryExpression binary = (BinaryExpression) parent;
if (binary.getOperationType() == PhpTokenTypes.opCONCAT) {
holder.registerProblem(operation, MessagesPresentationUtil.prefixWithEa(messageConcatenate), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new ReplaceWithArgumentFix());
return;
}
} else /* case 2: self assign with `... .= (string)...` */
if (parent instanceof SelfAssignmentExpression) {
final SelfAssignmentExpression assignment = (SelfAssignmentExpression) parent;
if (assignment.getOperationType() == PhpTokenTypes.opCONCAT_ASGN) {
holder.registerProblem(operation, MessagesPresentationUtil.prefixWithEa(messageConcatenate), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new ReplaceWithArgumentFix());
return;
}
}
}
/* case 3: un-needed due to types */
if (typesMapping.containsKey(operator)) {
final Set<String> types = this.resolveStrictly((PhpTypedElement) argument).getTypes();
if (types.size() == 1 && typesMapping.get(operator).equals(Types.getType(types.iterator().next()))) {
if (!(argument instanceof Variable) || !this.isWeakTypedParameter((Variable) argument)) {
final boolean isTarget = !this.isNullCoalescingOnly(argument);
if (isTarget) {
holder.registerProblem(operation, MessagesPresentationUtil.prefixWithEa(messageGeneric), ProblemHighlightType.LIKE_UNUSED_SYMBOL, new ReplaceWithArgumentFix());
}
}
}
}
}
}
private boolean isNullCoalescingOnly(@NotNull PsiElement argument) {
boolean result = false;
final Set<PsiElement> variants = PossibleValuesDiscoveryUtil.discover(argument);
if (variants.size() == 1) {
final PsiElement candidate = variants.iterator().next().getParent();
if (candidate instanceof BinaryExpression) {
result = ((BinaryExpression) candidate).getOperationType() == PhpTokenTypes.opCOALESCE;
}
}
variants.clear();
return result;
}
@NotNull
private PhpType resolveStrictly(@NotNull PhpTypedElement expression) {
final Project project = holder.getProject();
PhpType result = null;
if (expression instanceof FieldReference) {
/* fields has no type hints, hence private only */
final PsiElement resolved = OpenapiResolveUtil.resolveReference((FieldReference) expression);
if (resolved instanceof Field) {
final Field referencedField = (Field) resolved;
if (referencedField.getModifier().isPrivate()) {
result = OpenapiResolveUtil.resolveType(referencedField, project);
}
}
} else if (expression instanceof FunctionReference) {
/* requires implicit return type declaration */
final PsiElement resolved = OpenapiResolveUtil.resolveReference((FunctionReference) expression);
if (resolved instanceof Function) {
final Function referencedFunction = (Function) resolved;
final PsiElement returnedType = OpenapiElementsUtil.getReturnType(referencedFunction);
if (returnedType != null) {
result = OpenapiResolveUtil.resolveType(referencedFunction, project);
}
}
} else {
result = OpenapiResolveUtil.resolveType(expression, project);
}
/* Normalize the resolved types */
if (result != null && !result.isEmpty()) {
result = result.filterUnknown();
/* When `?->` operator is used, add null */
if (expression instanceof MemberReference) {
final MemberReference reference = (MemberReference) expression;
final PsiElement operator = OpenapiPsiSearchUtil.findResolutionOperator(reference);
if (OpenapiTypesUtil.is(operator, PhpTokenTypes.ARROW) && OpenapiTypesUtil.isNullSafeMemberReferenceOperator(operator)) {
result = new PhpType().add(result.filterNull()).add(PhpType.NULL);
}
}
return result;
}
return PhpType.EMPTY;
}
private boolean isWeakTypedParameter(@NotNull Variable variable) {
boolean result = false;
final Function scope = ExpressionSemanticUtil.getScope(variable);
if (scope != null) {
final String variableName = variable.getName();
for (final Parameter parameter : scope.getParameters()) {
if (parameter.getName().equals(variableName)) {
result = OpenapiResolveUtil.resolveDeclaredType(parameter).isEmpty();
break;
}
}
}
return result;
}
};
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType 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();
}
}
}
}
}
};
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class TypeUnsafeComparisonInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpBinaryExpression(@NotNull BinaryExpression expression) {
final IElementType operator = expression.getOperationType();
if (operator == PhpTokenTypes.opEQUAL || operator == PhpTokenTypes.opNOT_EQUAL) {
this.analyze(expression, operator);
}
}
private void analyze(@NotNull final BinaryExpression subject, @NotNull final IElementType operator) {
final String targetOperator = PhpTokenTypes.opEQUAL == operator ? "===" : "!==";
final PsiElement left = subject.getLeftOperand();
final PsiElement right = subject.getRightOperand();
if (right instanceof StringLiteralExpression || left instanceof StringLiteralExpression) {
final PsiElement nonStringOperand;
final String literalValue;
if (right instanceof StringLiteralExpression) {
literalValue = ((StringLiteralExpression) right).getContents();
nonStringOperand = ExpressionSemanticUtil.getExpressionTroughParenthesis(left);
} else {
literalValue = ((StringLiteralExpression) left).getContents();
nonStringOperand = ExpressionSemanticUtil.getExpressionTroughParenthesis(right);
}
/* resolve 2nd operand type, if class ensure __toString is implemented */
if (ClassInStringContextStrategy.apply(nonStringOperand, holder, subject, messageToStringMethodMissing)) {
/* TODO: weak warning regarding under-the-hood string casting */
return;
}
/* string literal is numeric or empty, no strict compare possible */
if (!literalValue.isEmpty() && !literalValue.matches("^[+-]?[0-9]*\\.?[0-9]+$")) {
holder.registerProblem(subject, String.format(MessagesPresentationUtil.prefixWithEa(patternCompareStrict), targetOperator), new CompareStrictFix(targetOperator));
return;
}
}
/* some objects supporting direct comparison: search for .compare_objects in PHP sources */
if (left != null && right != null) {
final boolean isComparableObject = this.isComparableObject(left) || this.isComparableObject(right);
if (!isComparableObject) {
holder.registerProblem(subject, String.format(MessagesPresentationUtil.prefixWithEa(patternHarden), targetOperator), ProblemHighlightType.WEAK_WARNING);
}
}
}
private boolean isComparableObject(@NotNull PsiElement operand) {
if (operand instanceof PhpTypedElement) {
final Project project = holder.getProject();
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) operand, project);
if (resolved != null) {
final PhpIndex index = PhpIndex.getInstance(project);
final Set<PhpClass> classes = new HashSet<>();
resolved.filterUnknown().getTypes().stream().filter(t -> t.charAt(0) == '\\').forEach(t -> classes.addAll(OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(Types.getType(t), index)));
for (final PhpClass clazz : classes) {
final boolean hasAny = comparable.contains(clazz.getFQN()) || InterfacesExtractUtil.getCrawlInheritanceTree(clazz, true).stream().anyMatch(c -> comparable.contains(c.getFQN()));
if (hasAny) {
classes.clear();
return true;
}
}
classes.clear();
}
}
return false;
}
};
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class InstanceofCanBeUsedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
final String functionName = reference.getName();
if (functionName != null) {
switch(functionName) {
case "get_class":
case "get_parent_class":
{
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 1 && this.isTargetBinaryContext(reference) && this.isNotString(arguments[0])) {
final BinaryExpression binary = (BinaryExpression) reference.getParent();
final PsiElement candidate = OpenapiElementsUtil.getSecondOperand(binary, reference);
if (candidate != null) {
final String fqn = this.extractClassFqn(candidate);
if (fqn != null) {
this.analyze(binary, arguments[0], fqn, !functionName.equals("get_class"));
}
}
}
break;
}
case "is_a":
case "is_subclass_of":
{
final PsiElement[] arguments = reference.getParameters();
final boolean isTarget = arguments.length == 2 || (arguments.length == 3 && PhpLanguageUtil.isFalse(arguments[2]));
if (isTarget && this.isNotString(arguments[0])) {
final String fqn = this.extractClassFqn(arguments[1]);
if (fqn != null) {
this.analyze(reference, arguments[0], fqn, true);
}
}
break;
}
case "in_array":
{
final PsiElement[] arguments = reference.getParameters();
if (arguments.length >= 2 && OpenapiTypesUtil.isFunctionReference(arguments[1])) {
final FunctionReference innerCall = (FunctionReference) arguments[1];
final String innerName = innerCall.getName();
if (innerName != null && (innerName.equals("class_implements") || innerName.equals("class_parents"))) {
final PsiElement[] innerArguments = innerCall.getParameters();
if (innerArguments.length > 0 && this.isNotString(innerArguments[0])) {
final String fqn = this.extractClassFqn(arguments[0]);
if (fqn != null) {
this.analyze(reference, innerArguments[0], fqn, true);
}
}
}
}
break;
}
}
}
}
private void analyze(@NotNull PsiElement context, @NotNull PsiElement subject, @NotNull String fqn, boolean allowChildClasses) {
final PhpIndex index = PhpIndex.getInstance(holder.getProject());
final Collection<PhpClass> classes = OpenapiResolveUtil.resolveClassesByFQN(fqn, index);
if (!classes.isEmpty() && (allowChildClasses || index.getDirectSubclasses(fqn).isEmpty())) {
boolean isInverted = false;
/* the calls can be inverted, less work for us */
if (context instanceof BinaryExpression) {
final IElementType operator = ((BinaryExpression) context).getOperationType();
isInverted = operator == PhpTokenTypes.opNOT_IDENTICAL || operator == PhpTokenTypes.opNOT_EQUAL;
}
final String replacement = String.format(isInverted ? "! %s instanceof %s" : "%s instanceof %s", subject.getText(), fqn);
holder.registerProblem(context, String.format(MessagesPresentationUtil.prefixWithEa(messagePattern), replacement), new UseInstanceofFix(replacement));
}
}
@Nullable
private String extractClassFqn(@NotNull PsiElement candidate) {
if (candidate instanceof StringLiteralExpression) {
final StringLiteralExpression string = (StringLiteralExpression) candidate;
final String clazz = string.getContents();
if (clazz.length() > 3 && !clazz.equals("__PHP_Incomplete_Class") && string.getFirstPsiChild() == null) {
return '\\' + clazz.replaceAll("\\\\\\\\", "\\\\");
}
}
return null;
}
private boolean isTargetBinaryContext(@NotNull FunctionReference reference) {
final PsiElement parent = reference.getParent();
if (parent instanceof BinaryExpression) {
return OpenapiTypesUtil.tsCOMPARE_EQUALITY_OPS.contains(((BinaryExpression) parent).getOperationType());
}
return false;
}
private boolean isNotString(@NotNull PsiElement subject) {
if (subject instanceof PhpTypedElement && !(subject instanceof StringLiteralExpression)) {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) subject, holder.getProject());
if (resolved != null && !resolved.hasUnknown()) {
return resolved.getTypes().stream().noneMatch(type -> Types.getType(type).equals(Types.strString));
}
}
return false;
}
};
}
use of com.jetbrains.php.lang.psi.resolve.types.PhpType in project phpinspectionsea by kalessil.
the class ReferenceMismatchInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
/**
* TODO: checkReferenceReturnedByCallable - ternary operator, argument usages ?
*/
/* parameters by reference */
@Override
public void visitPhpMethod(@NotNull Method method) {
/* PHP7 seems to be ref mismatch free */
final PhpLanguageLevel php = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (!php.hasFeature(PhpLanguageFeature.SCALAR_TYPE_HINTS)) {
this.checkParameters(method.getParameters(), method);
}
}
@Override
public void visitPhpFunction(@NotNull Function function) {
/* PHP7 seems to be ref mismatch free */
final PhpLanguageLevel phpVersion = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (phpVersion.hasFeature(PhpLanguageFeature.SCALAR_TYPE_HINTS)) {
// PHP7 and newer
return;
}
/* older versions are still affected */
this.checkParameters(function.getParameters(), function);
}
private void checkParameters(Parameter[] arrParameters, Function objScopeHolder) {
PhpEntryPointInstruction objEntryPoint = objScopeHolder.getControlFlow().getEntryPoint();
HashSet<PsiElement> emptyReportedItemsRegistry = ReferenceMismatchInspector.getFunctionReportingRegistry(objScopeHolder);
for (Parameter parameter : arrParameters) {
/* skip un-discoverable and non-reference parameters */
String strParameterName = parameter.getName();
if (!parameter.isPassByRef() || StringUtils.isEmpty(strParameterName)) {
continue;
}
inspectScopeForReferenceMissUsages(objEntryPoint, strParameterName, emptyReportedItemsRegistry);
}
emptyReportedItemsRegistry.clear();
}
/* = & variable/property patterns */
@Override
public void visitPhpAssignmentExpression(@NotNull AssignmentExpression assignmentExpression) {
/* PHP7 seems to be ref mismatch free */
final PhpLanguageLevel phpVersion = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (phpVersion.hasFeature(PhpLanguageFeature.SCALAR_TYPE_HINTS)) {
// PHP7 and newer
return;
}
/* older versions are still affected */
PsiElement value = assignmentExpression.getValue();
PsiElement variable = assignmentExpression.getVariable();
if (variable instanceof Variable && (value instanceof Variable || value instanceof FieldReference || value instanceof ArrayAccessExpression || value instanceof FunctionReference)) {
String strVariable = ((Variable) variable).getName();
PsiElement operation = value.getPrevSibling();
if (operation instanceof PsiWhiteSpace) {
operation = operation.getPrevSibling();
}
if (!StringUtils.isEmpty(strVariable) && null != operation && operation.getText().replaceAll("\\s+", "").equals("=&")) {
/* the case, scan for miss-usages assuming variable is unique */
Function scope = ExpressionSemanticUtil.getScope(assignmentExpression);
if (null != scope) {
// report items, but ensure no duplicated messages
HashSet<PsiElement> reportedItemsRegistry = ReferenceMismatchInspector.getFunctionReportingRegistry(scope);
inspectScopeForReferenceMissUsages(scope.getControlFlow().getEntryPoint(), strVariable, reportedItemsRegistry);
}
}
}
}
/* assign reference from function */
@Override
public void visitPhpMethodReference(@NotNull MethodReference reference) {
/* PHP7 seems to be ref mismatch free */
final PhpLanguageLevel phpVersion = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (phpVersion.hasFeature(PhpLanguageFeature.SCALAR_TYPE_HINTS)) {
// PHP7 and newer
return;
}
/* older versions are still affected */
this.checkReferenceReturnedByCallable(reference);
}
@Override
public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
/* PHP7 seems to be ref mismatch free */
final PhpLanguageLevel php = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (!php.hasFeature(PhpLanguageFeature.SCALAR_TYPE_HINTS)) {
this.checkReferenceReturnedByCallable(reference);
}
}
/* aggressive foreach optimization when value is reference */
@Override
public void visitPhpForeach(@NotNull ForeachStatement foreach) {
/* PHP7 seems to be ref mismatch free */
final PhpLanguageLevel phpVersion = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (phpVersion.hasFeature(PhpLanguageFeature.SCALAR_TYPE_HINTS)) {
// PHP7 and newer
return;
}
/* older versions are still affected */
/* lookup for reference preceding value */
Variable objForeachValue = foreach.getValue();
if (null != objForeachValue) {
String strVariable = objForeachValue.getName();
PsiElement prevElement = objForeachValue.getPrevSibling();
if (prevElement instanceof PsiWhiteSpace) {
prevElement = prevElement.getPrevSibling();
}
if (!StringUtils.isEmpty(strVariable) && OpenapiTypesUtil.is(prevElement, PhpTokenTypes.opBIT_AND)) {
/* the case, scan for miss-usages assuming value is unique */
Function scope = ExpressionSemanticUtil.getScope(foreach);
if (null != scope) {
// report items, but ensure no duplicated messages
HashSet<PsiElement> reportedItemsRegistry = ReferenceMismatchInspector.getFunctionReportingRegistry(scope);
reportedItemsRegistry.add(objForeachValue);
inspectScopeForReferenceMissUsages(scope.getControlFlow().getEntryPoint(), strVariable, reportedItemsRegistry);
}
}
}
}
private void inspectScopeForReferenceMissUsages(@NotNull PhpEntryPointInstruction objEntryPoint, @NotNull String strParameterName, @NotNull Set<PsiElement> reportedItemsRegistry) {
PsiElement previous;
PsiElement objExpression = null;
/* find usage inside scope */
PhpAccessVariableInstruction[] arrUsages = PhpControlFlowUtil.getFollowingVariableAccessInstructions(objEntryPoint, strParameterName, false);
for (final PhpAccessVariableInstruction objInstruction : arrUsages) {
previous = objExpression;
objExpression = objInstruction.getAnchor().getParent();
/* collided with foreach index/value => bug */
if (objExpression instanceof ForeachStatement) {
final ForeachStatement foreach = (ForeachStatement) objExpression;
if (previous instanceof PhpUnset) {
break;
}
final Variable foreachValue = foreach.getValue();
if (null != foreachValue && !StringUtils.isEmpty(foreachValue.getName()) && foreachValue.getName().equals(strParameterName)) {
if (!reportedItemsRegistry.contains(foreachValue)) {
reportedItemsRegistry.add(foreachValue);
holder.registerProblem(foreachValue, strErrorForeachIntoReference, ProblemHighlightType.ERROR);
}
continue;
}
final Variable foreachKey = foreach.getKey();
if (null != foreachKey && !StringUtils.isEmpty(foreachKey.getName()) && foreachKey.getName().equals(strParameterName)) {
if (!reportedItemsRegistry.contains(foreachKey)) {
reportedItemsRegistry.add(foreachKey);
holder.registerProblem(foreachKey, strErrorForeachIntoReference, ProblemHighlightType.ERROR);
}
continue;
}
}
/* test if provided as non-reference argument (copy dispatched) */
if (objExpression instanceof ParameterList && objExpression.getParent() instanceof FunctionReference) {
FunctionReference reference = (FunctionReference) objExpression.getParent();
/* not resolved or known re-unsafe function */
final PsiElement callable = OpenapiResolveUtil.resolveReference(reference);
if (!(callable instanceof Function)) {
continue;
}
final String strCallableName = ((Function) callable).getName();
if (!StringUtils.isEmpty(strCallableName) && legalizedMismatchingFunctions.contains(strCallableName)) {
continue;
}
/* check if call arguments contains our parameter */
int indexInArguments = -1;
boolean providedAsArgument = false;
for (PsiElement callArgument : reference.getParameters()) {
++indexInArguments;
if (callArgument instanceof Variable) {
Variable argument = (Variable) callArgument;
String argumentName = argument.getName();
if (!StringUtils.isEmpty(argumentName) && argumentName.equals(strParameterName)) {
providedAsArgument = true;
break;
}
}
}
/* if not found, keep processing usages */
if (!providedAsArgument) {
continue;
}
/* now check what is declared in resolved callable */
final Parameter[] usageCallableParameters = ((Function) callable).getParameters();
if (usageCallableParameters.length >= indexInArguments + 1) {
final Parameter parameter = usageCallableParameters[indexInArguments];
if (!parameter.isPassByRef()) {
/* additionally try filtering types for reducing false-positives on scalars */
final PhpType type = OpenapiResolveUtil.resolveType(parameter, holder.getProject());
if (type != null && !PhpType.isSubType(type, legalizedTypesForMismatchingSet)) {
final PsiElement target = reference.getParameters()[indexInArguments];
if (!reportedItemsRegistry.contains(target)) {
holder.registerProblem(target, "Reference mismatch, copy will be dispatched into function", ProblemHighlightType.WEAK_WARNING);
reportedItemsRegistry.add(target);
}
continue;
}
}
}
}
/* test is assigned to a variable without stating its reference (copy stored) */
if (objExpression instanceof AssignmentExpression) {
/* assignment structure verify */
AssignmentExpression assignment = (AssignmentExpression) objExpression;
if (assignment.getValue() instanceof Variable) {
Variable variable = (Variable) assignment.getValue();
String strVariable = variable.getName();
/* references parameter */
if (!StringUtils.isEmpty(strVariable) && strVariable.equals(strParameterName)) {
/* check if assignments states reference usage */
PsiElement operation = variable.getPrevSibling();
if (operation instanceof PsiWhiteSpace) {
operation = operation.getPrevSibling();
}
/* report if not */
if (null != operation && !operation.getText().replaceAll("\\s+", "").equals("=&")) {
if (!reportedItemsRegistry.contains(objExpression)) {
holder.registerProblem(objExpression, "Reference mismatch, copy will be stored (for non-objects)", ProblemHighlightType.WEAK_WARNING);
reportedItemsRegistry.add(objExpression);
}
}
}
}
}
}
}
private void checkReferenceReturnedByCallable(@NotNull FunctionReference reference) {
/* check context before resolving anything */
final PsiElement parent = reference.getParent();
if (parent instanceof AssignmentExpression) {
/* assignment structure verify */
final AssignmentExpression assignment = (AssignmentExpression) parent;
if (assignment.getValue() == reference) {
/* try resolving now */
final PsiElement callable = OpenapiResolveUtil.resolveReference(reference);
if (callable instanceof Function) {
/* ensure name discoverable */
final Function function = (Function) callable;
final PsiElement nameNode = NamedElementUtil.getNameIdentifier(function);
if (null != nameNode) {
/* is defined like returning reference */
PsiElement prevElement = nameNode.getPrevSibling();
if (prevElement instanceof PsiWhiteSpace) {
prevElement = prevElement.getPrevSibling();
}
if (OpenapiTypesUtil.is(prevElement, PhpTokenTypes.opBIT_AND)) {
/* check if assignments states reference usage */
PsiElement operation = reference.getPrevSibling();
if (operation instanceof PsiWhiteSpace) {
operation = operation.getPrevSibling();
}
/* report if not */
if (null != operation && !operation.getText().replaceAll("\\s+", "").equals("=&")) {
holder.registerProblem(parent, "Reference mismatch, copy will be stored (for non-objects)", ProblemHighlightType.WEAK_WARNING);
}
}
}
}
}
}
}
};
}
Aggregations