use of com.jetbrains.php.config.PhpLanguageLevel in project phpinspectionsea by kalessil.
the class PropertyInitializationFlawsInspectorTest method testTypedPropertiesPatterns.
public void testTypedPropertiesPatterns() {
final PhpLanguageLevel level = PhpLanguageLevel.parse("7.4");
if (level != null && level.getVersionString().equals("7.4")) {
PhpProjectConfigurationFacade.getInstance(myFixture.getProject()).setLanguageLevel(level);
myFixture.enableInspections(new PropertyInitializationFlawsInspector());
myFixture.configureByFile("testData/fixtures/codeStyle/property-initialization-typed-properties.php");
myFixture.testHighlighting(true, false, true);
}
}
use of com.jetbrains.php.config.PhpLanguageLevel 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);
}
}
}
}
}
}
}
};
}
use of com.jetbrains.php.config.PhpLanguageLevel in project phpinspectionsea by kalessil.
the class AccessModifierPresentedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpClass(@NotNull PhpClass clazz) {
/* community request: interfaces have only public methods, what is default access levels */
if (!ANALYZE_INTERFACES && clazz.isInterface()) {
return;
}
/* inspect methods */
for (final Method method : clazz.getOwnMethods()) {
final PsiElement methodName = NamedElementUtil.getNameIdentifier(method);
if (methodName != null && method.getAccess().isPublic()) {
final PhpModifierList modifiers = PsiTreeUtil.findChildOfType(method, PhpModifierList.class);
if (modifiers != null && !modifiers.getText().toLowerCase().contains("public")) {
final String message = String.format(messagePattern, method.getName());
holder.registerProblem(methodName, message, new MemberVisibilityFix(modifiers));
}
}
}
/* inspect fields */
final PhpLanguageLevel phpVersion = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
final boolean checkConstantVisibility = phpVersion.compareTo(PhpLanguageLevel.PHP710) >= 0;
for (final Field field : clazz.getOwnFields()) {
final PsiElement fieldName = NamedElementUtil.getNameIdentifier(field);
if (fieldName != null && field.getModifier().isPublic()) {
if (field.isConstant()) {
/* {const}.isPublic() always returns true, even if visibility is not declared */
if (ANALYZE_CONSTANTS && checkConstantVisibility && field.getPrevPsiSibling() == null) {
final String message = String.format(messagePattern, field.getName());
holder.registerProblem(fieldName, message, new ConstantVisibilityFix(field));
}
} else {
final PhpModifierList modifiers = PsiTreeUtil.findChildOfType(field.getParent(), PhpModifierList.class);
if (modifiers != null && !modifiers.getText().toLowerCase().contains("public")) {
final String message = String.format(messagePattern, field.getName());
holder.registerProblem(fieldName, message, new MemberVisibilityFix(modifiers));
}
}
}
}
}
};
}
use of com.jetbrains.php.config.PhpLanguageLevel in project phpinspectionsea by kalessil.
the class PowerOperatorCanBeUsedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) {
return new BasePhpElementVisitor() {
@Override
public void visitPhpFunctionCall(@NotNull FunctionReference reference) {
final PhpLanguageLevel php = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (php.compareTo(PhpLanguageLevel.PHP560) >= 0) {
final String functionName = reference.getName();
if (functionName != null && functionName.equals("pow")) {
final PsiElement[] arguments = reference.getParameters();
if (arguments.length == 2) {
final String replacement = (reference.getParent() instanceof BinaryExpression ? "(%b% ** %p%)" : "%b% ** %p%").replace("%p%", arguments[1] instanceof BinaryExpression ? "(%p%)" : "%p%").replace("%b%", arguments[0] instanceof BinaryExpression ? "(%b%)" : "%b%").replace("%p%", arguments[1].getText()).replace("%b%", arguments[0].getText());
holder.registerProblem(reference, String.format(messagePattern, replacement), new UseTheOperatorFix(replacement));
}
}
}
}
};
}
use of com.jetbrains.php.config.PhpLanguageLevel in project phpinspectionsea by kalessil.
the class ShortListSyntaxCanBeUsedInspector method buildVisitor.
@Override
@NotNull
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, final boolean isOnTheFly) {
return new BasePhpElementVisitor() {
public void visitPhpMultiassignmentExpression(MultiassignmentExpression multiassignmentExpression) {
/* ensure php version is at least PHP 7.1 */
final PhpLanguageLevel phpVersion = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (phpVersion.compareTo(PhpLanguageLevel.PHP710) < 0) {
return;
}
/* verify if it's dedicated statement and it's the list(...) construction */
final PsiElement parent = multiassignmentExpression.getParent();
if (!OpenapiTypesUtil.isStatementImpl(parent)) {
return;
}
final PsiElement listKeyword = multiassignmentExpression.getFirstChild();
if (null != listKeyword && PhpTokenTypes.kwLIST == listKeyword.getNode().getElementType()) {
holder.registerProblem(listKeyword, messageAssign, ProblemHighlightType.WEAK_WARNING, new TheLocalFix());
}
}
public void visitPhpForeach(ForeachStatement foreach) {
/* ensure php version is at least PHP 7.1 */
final PhpLanguageLevel phpVersion = PhpProjectConfigurationFacade.getInstance(holder.getProject()).getLanguageLevel();
if (phpVersion.compareTo(PhpLanguageLevel.PHP710) < 0) {
return;
}
final List<Variable> variables = foreach.getVariables();
if (variables.size() > 0) {
PsiElement childNode = foreach.getFirstChild();
while (null != childNode) {
if (childNode.getClass() == LeafPsiElement.class && PhpTokenTypes.kwLIST == childNode.getNode().getElementType()) {
holder.registerProblem(childNode, messageForeach, ProblemHighlightType.WEAK_WARNING, new TheLocalFix());
break;
}
childNode = childNode.getNextSibling();
if (childNode instanceof GroupStatement) {
break;
}
}
}
}
};
}
Aggregations