use of com.kalessil.phpStorm.phpInspectionsEA.utils.Types in project phpinspectionsea by kalessil.
the class ComparableCoreClassesStrategy method isComparableObject.
private static boolean isComparableObject(@NotNull PsiElement operand, @NotNull PhpIndex index) {
/* extract types of operand, check if classes are/inherited from \DateTime */
final Set<String> operandTypes = new HashSet<>();
if (operand instanceof PhpTypedElement) {
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) operand, operand.getProject());
if (resolved != null) {
resolved.filterUnknown().getTypes().forEach(t -> operandTypes.add(Types.getType(t)));
}
}
if (!TypesSemanticsUtil.isNullableObjectInterface(operandTypes)) {
operandTypes.clear();
return false;
}
/* collect classes to check for \DateTime relationship */
final List<PhpClass> operandClasses = new ArrayList<>();
operandTypes.stream().filter(fqn -> fqn.charAt(0) == '\\').forEach(fqn -> operandClasses.addAll(OpenapiResolveUtil.resolveClassesAndInterfacesByFQN(fqn, index)));
operandTypes.clear();
/* inspect classes for being a/child of special once */
for (final PhpClass clazz : operandClasses) {
final HashSet<PhpClass> hierarchy = InterfacesExtractUtil.getCrawlInheritanceTree(clazz, true);
for (final PhpClass oneClass : hierarchy) {
if (comparableObjects.contains(oneClass.getFQN())) {
return true;
}
}
hierarchy.clear();
}
operandClasses.clear();
return false;
}
use of com.kalessil.phpStorm.phpInspectionsEA.utils.Types in project phpinspectionsea by kalessil.
the class CollectPossibleThrowsUtil method collectNestedAndWorkflowExceptions.
public static HashMap<PhpClass, HashSet<PsiElement>> collectNestedAndWorkflowExceptions(PsiElement scope, HashSet<PsiElement> processed, @NotNull final ProblemsHolder holder) {
final HashMap<PhpClass, HashSet<PsiElement>> exceptions = new HashMap<>();
/* recursively invoke and analyse nested try-catches checks */
final Collection<Try> tryStatements = PsiTreeUtil.findChildrenOfType(scope, Try.class);
if (tryStatements.size() > 0) {
for (Try nestedTry : tryStatements) {
if (!processed.contains(nestedTry)) {
/* process nested workflow */
final HashMap<PhpClass, HashSet<PsiElement>> nestedTryExceptions = collectNestedAndWorkflowExceptions(nestedTry, processed, holder);
// holder.registerProblem(nestedTry.getFirstChild(), "Nested: " + nestedTryExceptions.toString(), ProblemHighlightType.WEAK_WARNING);
if (nestedTryExceptions.size() > 0) {
for (final Map.Entry<PhpClass, HashSet<PsiElement>> nestedTryExceptionsPair : nestedTryExceptions.entrySet()) {
/* extract pairs Exception class => source expressions */
final PhpClass key = nestedTryExceptionsPair.getKey();
final HashSet<PsiElement> expressionsToDispatch = nestedTryExceptionsPair.getValue();
if (exceptions.containsKey(key)) {
/* merge entries and release refs */
exceptions.get(key).addAll(expressionsToDispatch);
expressionsToDispatch.clear();
} else {
/* store as it is */
exceptions.put(key, expressionsToDispatch);
}
}
nestedTryExceptions.clear();
}
}
}
tryStatements.clear();
}
/* process try-catch */
if (scope instanceof Try) {
/* extract workflow exceptions */
HashMap<PhpClass, HashSet<PsiElement>> tryWorkflowExceptions = collectTryWorkflowExceptions((Try) scope, processed, holder);
// holder.registerProblem(scope.getFirstChild(), "Throws: " + tryWorkflowExceptions.toString(), ProblemHighlightType.WEAK_WARNING);
/* mark processed and exit, as try-catch handled in special way */
processed.add(scope);
exceptions.clear();
return tryWorkflowExceptions;
}
/* process new statements: throws, constructors */
Collection<NewExpression> newExpressions = PsiTreeUtil.findChildrenOfType(scope, NewExpression.class);
if (newExpressions.size() > 0) {
for (NewExpression newExpression : newExpressions) {
/* skip processed */
if (processed.contains(newExpression)) {
continue;
}
// holder.registerProblem(newExpression, "New expression wil be analyzed", ProblemHighlightType.WEAK_WARNING);
/* skip what can not be resolved */
ClassReference newClassRef = newExpression.getClassReference();
if (null == newClassRef) {
processed.add(newExpression);
continue;
}
PhpClass newClass;
final PsiElement resolved = OpenapiResolveUtil.resolveReference(newClassRef);
if (resolved instanceof PhpClass) {
newClass = (PhpClass) resolved;
} else if (resolved instanceof Method) {
newClass = ((Method) resolved).getContainingClass();
} else {
processed.add(newExpression);
continue;
}
/* throws processed */
if (newExpression.getParent() instanceof PhpThrow) {
/* put an expression, create container if necessary */
if (!exceptions.containsKey(newClass)) {
exceptions.put(newClass, new HashSet<>());
}
exceptions.get(newClass).add(newExpression.getParent());
processed.add(newExpression);
continue;
}
/* process constructors invocation */
final Method constructor = newClass == null ? null : newClass.getConstructor();
if (constructor != null) {
// holder.registerProblem(newExpression, "Constructor found", ProblemHighlightType.WEAK_WARNING);
/* lookup for annotated exceptions */
final HashSet<PhpClass> constructorExceptions = new HashSet<>();
ThrowsResolveUtil.resolveThrownExceptions(constructor, constructorExceptions);
/* link expression with each possible exception */
if (constructorExceptions.size() > 0) {
for (PhpClass constructorException : constructorExceptions) {
/* put an expression, create container if necessary */
if (!exceptions.containsKey(constructorException)) {
exceptions.put(constructorException, new HashSet<>());
}
exceptions.get(constructorException).add(newExpression.getParent());
}
constructorExceptions.clear();
}
}
processed.add(newExpression);
}
newExpressions.clear();
}
/* process throws - some of them might not use new-expression */
final Project project = holder.getProject();
final PhpIndex objIndex = PhpIndex.getInstance(project);
Collection<PhpThrow> throwExpressions = PsiTreeUtil.findChildrenOfType(scope, PhpThrow.class);
if (!throwExpressions.isEmpty()) {
for (final PhpThrow throwExpression : throwExpressions) {
/* skip processed */
if (processed.contains(throwExpression)) {
continue;
}
/* resolve argument */
final PsiElement argument = throwExpression.getArgument();
if (argument instanceof PhpTypedElement) {
/* resolve argument types */
final HashSet<String> types = new HashSet<>();
final PhpType resolved = OpenapiResolveUtil.resolveType((PhpTypedElement) argument, project);
if (resolved != null) {
resolved.filterUnknown().getTypes().forEach(t -> types.add(Types.getType(t)));
}
if (!types.isEmpty()) {
/* remove extra definition of \Exception unexpectedly added by PhpStorm */
final boolean dropExtraDefinitions = argument instanceof Variable && types.size() > 1 && types.contains("\\Exception");
if (dropExtraDefinitions) {
types.remove("\\Exception");
}
for (final String type : types) {
if (type.startsWith("\\")) {
/* process classes references */
final Collection<PhpClass> classes = OpenapiResolveUtil.resolveClassesByFQN(type, objIndex);
if (!classes.isEmpty()) {
/* put an expression, create container if necessary */
final PhpClass exception = classes.iterator().next();
exceptions.computeIfAbsent(exception, e -> new HashSet<>()).add(throwExpression);
}
}
}
types.clear();
}
}
processed.add(throwExpression);
}
throwExpressions.clear();
}
/* process nested calls */
Collection<MethodReference> calls = PsiTreeUtil.findChildrenOfType(scope, MethodReference.class);
if (calls.size() > 0) {
for (MethodReference call : calls) {
/* skip processed */
if (processed.contains(call)) {
continue;
}
PsiElement methodResolved = OpenapiResolveUtil.resolveReference(call);
if (methodResolved instanceof Method) {
/* lookup for annotated exceptions */
final HashSet<PhpClass> methodExceptions = new HashSet<>();
ThrowsResolveUtil.resolveThrownExceptions((Method) methodResolved, methodExceptions);
/* link expression with each possible exception */
if (methodExceptions.size() > 0) {
for (PhpClass methodException : methodExceptions) {
/* put an expression, create container if necessary */
if (!exceptions.containsKey(methodException)) {
exceptions.put(methodException, new HashSet<>());
}
exceptions.get(methodException).add(call);
}
methodExceptions.clear();
}
}
processed.add(call);
}
calls.clear();
}
return exceptions;
}
Aggregations