mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-19 04:51:24 +07:00
[java-highlighting] IDEA-353117 Error highlighting in the incomplete project model
- prevent infinite recursion with parameters. `com.intellij.codeInsight.daemon.impl.analysis.IncompleteModelUtil.hasUnresolvedComponent` can be called infinitely with parameters for ClassA<T extends ClassA<T>>, where T is captured `?` GitOrigin-RevId: 60e44f537f04a3bf817493ff40eb227851bf1821
This commit is contained in:
committed by
intellij-monorepo-bot
parent
dcd9d3a218
commit
122bc7ffc3
@@ -80,24 +80,32 @@ final class IncompleteModelUtil {
|
||||
*/
|
||||
@Contract("null -> false")
|
||||
static boolean hasUnresolvedComponent(@Nullable PsiType psiType) {
|
||||
return hasUnresolvedComponentRecursively(psiType, new HashSet<>());
|
||||
}
|
||||
|
||||
private static boolean hasUnresolvedComponentRecursively(@Nullable PsiType psiType, @NotNull HashSet<PsiClass> visited) {
|
||||
if (psiType == null) return false;
|
||||
PsiType type = psiType.getDeepComponentType();
|
||||
if (isUnresolvedClassType(psiType)) {
|
||||
return true;
|
||||
}
|
||||
if (type instanceof PsiClassType classType) {
|
||||
PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(classType);
|
||||
if (psiClass != null && !visited.add(psiClass)) {
|
||||
return false;
|
||||
}
|
||||
for (PsiType parameter : classType.getParameters()) {
|
||||
if (hasUnresolvedComponent(parameter)) {
|
||||
if (hasUnresolvedComponentRecursively(parameter, visited)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type instanceof PsiWildcardType wildcardType) {
|
||||
return hasUnresolvedComponent(wildcardType.getBound());
|
||||
return hasUnresolvedComponentRecursively(wildcardType.getBound(), visited);
|
||||
}
|
||||
if (type instanceof PsiCapturedWildcardType capturedWildcardType) {
|
||||
return hasUnresolvedComponent(capturedWildcardType.getLowerBound()) ||
|
||||
hasUnresolvedComponent(capturedWildcardType.getUpperBound());
|
||||
return hasUnresolvedComponentRecursively(capturedWildcardType.getLowerBound(), visited) ||
|
||||
hasUnresolvedComponentRecursively(capturedWildcardType.getUpperBound(), visited);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import org.<info descr="Not resolved until the project is fully loaded">springframework</info>.<info descr="Not resolved until the project is fully loaded">lang</info>.<info descr="Not resolved until the project is fully loaded">NonNull</info>;
|
||||
import org.<info descr="Not resolved until the project is fully loaded">example</info>.<info descr="Not resolved until the project is fully loaded">lombokdumbmode</info>.<info descr="Not resolved until the project is fully loaded">model</info>.<info descr="Not resolved until the project is fully loaded">chain</info>.<info descr="Not resolved until the project is fully loaded">UserChain</info>;
|
||||
import org.<info descr="Not resolved until the project is fully loaded">springframework</info>.<info descr="Not resolved until the project is fully loaded">boot</info>.<info descr="Not resolved until the project is fully loaded">autoconfigure</info>.<info descr="Not resolved until the project is fully loaded">Request</info>;
|
||||
import <info descr="Not resolved until the project is fully loaded">a</info>.*;
|
||||
|
||||
@<info descr="Not resolved until the project is fully loaded">SpringBootApplication</info>
|
||||
public class LombokDumbModeApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
<info descr="Not resolved until the project is fully loaded">Request</info> a = new <info descr="Not resolved until the project is fully loaded">Request</info>();
|
||||
<error descr="Incompatible types. Found: 'capture<?>', required: 'UserDao'">UserDao userDao = UserDao.builder()
|
||||
.id(1)
|
||||
.name("2")
|
||||
.surname("3")
|
||||
.email("4")
|
||||
.name("1")</error><error descr="';' expected">a</error>
|
||||
.<info descr="Not resolved until the project is fully loaded">id</info>(1)
|
||||
.<info descr="Not resolved until the project is fully loaded">build</info>();
|
||||
|
||||
String name = userDao
|
||||
.nhaame();
|
||||
<info descr="Not resolved until the project is fully loaded">UserChain</info> userChain = new <info descr="Not resolved until the project is fully loaded">UserChain</info>();
|
||||
String name1 = userChain.<info descr="Not resolved until the project is fully loaded">getName</info>();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class UserDao extends UserId {
|
||||
@<info descr="Not resolved until the project is fully loaded">NonNull</info>
|
||||
private final String nhaame;
|
||||
@<info descr="Not resolved until the project is fully loaded">NonNull</info>
|
||||
private final String surname;
|
||||
@<info descr="Not resolved until the project is fully loaded">NonNull</info>
|
||||
private final String email;
|
||||
|
||||
protected UserDao(UserDaoBuilder<?, ?> b) {
|
||||
super(b);
|
||||
this.nhaame = b.nhaame;
|
||||
this.surname = b.surname;
|
||||
this.email = b.email;
|
||||
}
|
||||
|
||||
public static UserDaoBuilder<?, ?> builder() {
|
||||
return new UserDaoBuilderImpl();
|
||||
}
|
||||
|
||||
public String nhaame() {
|
||||
return this.nhaame;
|
||||
}
|
||||
|
||||
public String surname() {
|
||||
return this.surname;
|
||||
}
|
||||
|
||||
public String email() {
|
||||
return this.email;
|
||||
}
|
||||
|
||||
public static abstract class UserDaoBuilder<C extends UserDao, B extends UserDaoBuilder<C, B>> extends UserIdBuilder<C, B> {
|
||||
private String nhaame;
|
||||
private String surname;
|
||||
private String email;
|
||||
|
||||
public B name(String nhaame) {
|
||||
this.nhaame = nhaame;
|
||||
return self();
|
||||
}
|
||||
|
||||
public B surname(String surname) {
|
||||
this.surname = surname;
|
||||
return self();
|
||||
}
|
||||
|
||||
public B email(String email) {
|
||||
this.email = email;
|
||||
return self();
|
||||
}
|
||||
|
||||
protected abstract B self();
|
||||
|
||||
public abstract C build();
|
||||
|
||||
public String toString() {
|
||||
return "UserDao.UserDaoBuilder(super=" + super.toString() + ", nhaame=" + this.nhaame + ", surname=" + this.surname + ", email=" + this.email + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private static final class UserDaoBuilderImpl extends UserDaoBuilder<UserDao, UserDaoBuilderImpl> {
|
||||
private UserDaoBuilderImpl() {
|
||||
}
|
||||
|
||||
protected UserDaoBuilderImpl self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserDao build() {
|
||||
return new UserDao(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class UserId {
|
||||
private final long id;
|
||||
private final String info;
|
||||
|
||||
protected UserId(UserIdBuilder<?, ?> b) {
|
||||
this.id = b.id;
|
||||
this.info = b.info;
|
||||
}
|
||||
|
||||
public static abstract class UserIdBuilder<C extends UserId, B extends UserIdBuilder<C, B>> {
|
||||
private long id;
|
||||
private String info;
|
||||
|
||||
public B id(long id) {
|
||||
this.id = id;
|
||||
return self();
|
||||
}
|
||||
|
||||
public B info(String info) {
|
||||
this.info = info;
|
||||
return self();
|
||||
}
|
||||
|
||||
protected abstract B self();
|
||||
|
||||
public abstract C build();
|
||||
|
||||
public String toString() {
|
||||
return "UserId.UserIdBuilder(id=" + this.id + ", info=" + this.info + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,4 +33,6 @@ public final class IncompleteModelHighlightingTest extends LightDaemonAnalyzerTe
|
||||
public void testServer() { doTest(); }
|
||||
|
||||
public void testStarImports() { doTest(); }
|
||||
|
||||
public void testIncompleteRecursiveParameters() { doTest(); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user