void (@NotNull final UElement decl, @NotNull final RefJavaElement ref, final UElement @Nullable ... findIn) { final RefJavaElementImpl refFrom = (RefJavaElementImpl)ref; final RefManagerImpl refManager = refFrom.getRefManager(); if (findIn == null) { return; } for (UElement element : findIn) { if (element == null) continue; element.accept(new AbstractUastVisitor() { @Override public boolean visitEnumConstant(@NotNull UEnumConstant node) { processNewLikeConstruct(node.resolve(), node); return false; } @Override public boolean visitAnnotation(@NotNull UAnnotation node) { PsiClass javaClass = node.resolve(); if (javaClass != null) { final RefElement refClass = refManager.getReference(javaClass.getOriginalElement()); if (refClass != null) refClass.initializeIfNeeded(); refFrom.addReference(refClass, javaClass.getOriginalElement(), decl, false, true, null); } return false; } @Override public boolean visitTypeReferenceExpression(@NotNull UTypeReferenceExpression node) { PsiType type = node.getType(); visitTypeRefs(type); return false; } private void visitTypeRefs(PsiType type) { type = type.getDeepComponentType(); if (type instanceof PsiClassType) { type.accept(new PsiTypeVisitor<Void>() { @Override public Void visitClassType(@NotNull PsiClassType classType) { for (PsiType parameter : classType.getParameters()) { parameter.accept(this); } UClass target = UastContextKt.toUElement(classType.resolve(), UClass.class); if (target != null) { final RefElement refElement = refManager.getReference(target.getSourcePsi()); if (refElement != null) refElement.initializeIfNeeded(); refFrom.addReference(refElement, target.getSourcePsi(), decl, false, true, null); } return null; } }); } } @Override public boolean visitVariable(@NotNull UVariable node) { visitTypeRefs(node.getType()); return false; } @Override public boolean visitSimpleNameReferenceExpression(@NotNull USimpleNameReferenceExpression node) { visitReferenceExpression(node); return false; } @Override public boolean visitLiteralExpression(@NotNull ULiteralExpression node) { PsiElement sourcePsi = node.getSourcePsi(); if (sourcePsi != null) { for (PsiReference reference : sourcePsi.getReferences()) { PsiElement resolve = reference.resolve(); if (resolve instanceof PsiMember) { final RefElement refResolved = refManager.getReference(resolve); if (refResolved != null) refResolved.initializeIfNeeded(); refFrom.addReference(refResolved, resolve, decl, false, true, null); if (refResolved instanceof RefMethodImpl refMethod) { updateRefMethod(resolve, refMethod, node, decl); } } } } return false; } @Override public boolean visitPrefixExpression(@NotNull UPrefixExpression node) { visitReferenceExpression(node); return false; } @Override public boolean visitPostfixExpression(@NotNull UPostfixExpression node) { visitReferenceExpression(node); return false; } @Override public boolean visitUnaryExpression(@NotNull UUnaryExpression node) { visitReferenceExpression(node); return false; } @Override public boolean visitBinaryExpression(@NotNull UBinaryExpression node) { visitReferenceExpression(node); return false; } @Override public boolean visitQualifiedReferenceExpression(@NotNull UQualifiedReferenceExpression node) { visitReferenceExpression(node); return false; } @Override public boolean visitObjectLiteralExpression(@NotNull UObjectLiteralExpression node) { visitReferenceExpression(node); visitClass(node.getDeclaration()); return false; } @Override public boolean visitCallExpression(@NotNull UCallExpression node) { visitReferenceExpression(node); if (node instanceof UObjectLiteralExpression objectLiteralExpression) { visitClass(objectLiteralExpression.getDeclaration()); } if (node.getKind() == UastCallKind.CONSTRUCTOR_CALL) { PsiElement resolvedMethod = returnToPhysical(node.resolve()); RefMethod refConstructor = processNewLikeConstruct(resolvedMethod, node); if (refConstructor == null) { // No explicit constructor referenced. Should use default one. UReferenceExpression reference = node.getClassReference(); if (reference != null) { PsiElement constructorClass = reference.resolve(); if (constructorClass instanceof PsiClass psiClass) { processClassReference(psiClass, true, node); } } } } try { node.getTypeArguments().forEach(this::visitTypeRefs); } catch (UnsupportedOperationException e) { //TODO happens somewhere in kotlin plugin. Please assign those exception for Dmitry Batkovich LOG.error(e); } return false; } private void visitReferenceExpression(@NotNull UExpression node) { UElement uastParent = node.getUastParent(); if (uastParent instanceof UQualifiedReferenceExpression qualifiedReference && qualifiedReference.getSelector() == node) { return; } PsiElement psiResolved = null; if (node instanceof UCallExpression callExpression && "invoke".equals(callExpression.getMethodName()) && callExpression.getReceiver() instanceof UResolvable resolvable) { psiResolved = resolvable.resolve(); } else if (node instanceof UResolvable resolvable) { psiResolved = resolvable.resolve(); } else if (node instanceof UBinaryExpression binaryExpression) { psiResolved = binaryExpression.resolveOperator(); } else if (node instanceof UUnaryExpression unaryExpression) { psiResolved = unaryExpression.resolveOperator(); } psiResolved = returnToPhysical(psiResolved); RefElement refResolved = refManager.getReference(psiResolved); boolean writing = isAccessedForWriting(node); boolean reading = isAccessedForReading(node); if (refResolved != null) refResolved.initializeIfNeeded(); refFrom.initializeIfNeeded(); refFrom.addReference(refResolved, psiResolved, decl, writing, reading, node); if (refResolved instanceof RefMethodImpl refMethod) { updateRefMethod(psiResolved, refMethod, node, decl); } else if (refResolved instanceof RefField) { if (node instanceof UResolvable resolvable) { UMethod uProperty = UastContextKt.toUElement(resolvable.resolve(), UMethod.class); if (uProperty != null) { // PsiMethod property = uProperty.getJavaPsi(); // RefElement refProperty = refManager.getReference(uProperty); // if (refProperty != null) { // refProperty.waitForInitialized(); // refFrom.addReference(refProperty, property, decl, false, true, node); // } } } } if (psiResolved instanceof PsiMember psiMember) { //TODO support kotlin addClassReferenceForStaticImport(node, psiMember, refFrom, decl); } } @Override public boolean visitLambdaExpression(@NotNull ULambdaExpression lambda) { processFunctionalExpression(lambda, lambda.getFunctionalInterfaceType()); return true; } @Override public boolean visitCallableReferenceExpression(@NotNull UCallableReferenceExpression methodRef) { UExpression qualifierExpression = methodRef.getQualifierExpression(); if (qualifierExpression != null) { qualifierExpression.accept(this); } RefElement refMethod = refManager.getReference(methodRef.getSourcePsi()); if (refFrom == refMethod) { visitReferenceExpression(methodRef); return false; } else { processFunctionalExpression(methodRef, getFunctionalInterfaceType(methodRef)); return true; } } private void processFunctionalExpression(@NotNull UExpression expression, @Nullable PsiType type) { PsiElement aClass = PsiUtil.resolveClassInType(type); if (aClass != null) { aClass = ((PsiClass)aClass).getSourceElement(); } if (aClass != null) { final RefElement refWhat = refManager.getReference(aClass); if (refWhat != null) refWhat.initializeIfNeeded(); refFrom.addReference(refWhat, aClass, decl, false, true, null); } PsiElement functionalExpr = expression.getSourcePsi(); RefElement refFunctionalExpr = refManager.getReference(functionalExpr); if (refFunctionalExpr != null) refFunctionalExpr.initializeIfNeeded(); refFrom.addReference(refFunctionalExpr, functionalExpr, decl, false, true, expression); } @Nullable private RefMethod processNewLikeConstruct(PsiElement javaConstructor, UCallExpression call) { if (javaConstructor == null) return null; RefMethodImpl refConstructor = ObjectUtils.tryCast(refManager.getReference(javaConstructor.getOriginalElement()), RefMethodImpl.class); refFrom.addReference(refConstructor, javaConstructor, decl, false, true, null); for (UExpression arg : call.getValueArguments()) { arg.accept(this); } if (refConstructor != null) { refConstructor.initializeIfNeeded(); refConstructor.updateParameterValues(call, javaConstructor); } return refConstructor; } @Override public boolean visitClass(@NotNull UClass uClass) { for (UTypeReferenceExpression type : uClass.getUastSuperTypes()) { type.accept(this); } PsiElement sourcePsi = uClass.getSourcePsi(); RefElement refWhat = refManager.getReference(sourcePsi); if (refWhat != null) refWhat.initializeIfNeeded(); refFrom.addReference(refWhat, sourcePsi, decl, false, true, null); return true; } @Override public boolean visitReturnExpression(@NotNull UReturnExpression node) { RefMethodImpl refMethod = null; if (refFrom instanceof RefMethodImpl && UastUtils.getParentOfType(node, UMethod.class, false, UClass.class, ULambdaExpression.class) == decl) { refMethod = (RefMethodImpl)refFrom; } else if (refFrom instanceof RefFunctionalExpression) { UElement target = node.getJumpTarget(); if (target instanceof UMethod) { refMethod = ObjectUtils.tryCast(refManager.getReference(target.getSourcePsi()), RefMethodImpl.class); } else if (decl instanceof ULambdaExpression lambdaExpression) { PsiMethod lambdaMethod = LambdaUtil.getFunctionalInterfaceMethod(lambdaExpression.getFunctionalInterfaceType()); refMethod = ObjectUtils.tryCast(refManager.getReference(lambdaMethod), RefMethodImpl.class); } } if (refMethod != null) { refMethod.initializeIfNeeded(); refMethod.updateReturnValueTemplate(node.getReturnExpression()); } return false; } @Override public boolean visitClassLiteralExpression(@NotNull UClassLiteralExpression node) { processClassReference(PsiUtil.resolveClassInClassTypeOnly(node.getType()), false, node); return false; } private void processClassReference(PsiClass psiClass, boolean defaultConstructorOnly, UExpression node) { if (psiClass != null) { RefClassImpl refClass = ObjectUtils.tryCast(refManager.getReference(psiClass.getNavigationElement()), RefClassImpl.class); if (refClass != null) { boolean hasConstructorsMarked = false; refClass.initializeIfNeeded(); if (defaultConstructorOnly) { WritableRefElement refDefaultConstructor = (WritableRefElement)refClass.getDefaultConstructor(); if (refDefaultConstructor != null) { refDefaultConstructor.addInReference(refFrom); refFrom.addOutReference(refDefaultConstructor); hasConstructorsMarked = true; } } else { for (RefMethod cons : refClass.getConstructors()) { if (cons instanceof RefImplicitConstructor) continue; ((WritableRefElement)cons).addInReference(refFrom); refFrom.addOutReference(cons); hasConstructorsMarked = true; } if (refClass.isEnum()) { for (RefField field : refClass.getFields()) { if (field.isEnumConstant()) { ((RefFieldImpl)field).markReferenced(refFrom, false, true, node); refFrom.addOutReference(field); } } } } if (!hasConstructorsMarked) { refFrom.addReference(refClass, psiClass, decl, false, true, node); } } } } } ); } }