[jps model] speed up JpsNamedElementReferenceBase::resolve method (IDEA-368571)

Before it iterated over all elements in the collection to find the element by name. Now, a special interface JpsNamedElementCollection with corresponding JpsNamedElementCollectionRole is introduced. Its implementation maintains a map from names to elements, allowing quickly finding an element by its name.


(cherry picked from commit c9e83186586f81c25cab67b261ab3a8b74102f99)

IJ-CR-157018

GitOrigin-RevId: 7d82b41d392bba5600660d9968c6211b7de0689e
This commit is contained in:
Nikolay Chashnikov
2025-03-06 17:23:51 +01:00
committed by intellij-monorepo-bot
parent d3a7dcfa0a
commit b12ca91066
14 changed files with 190 additions and 27 deletions

View File

@@ -102,6 +102,9 @@ org.jetbrains.jps.model.JpsNamedElement
- org.jetbrains.jps.model.JpsElement
- a:getName():java.lang.String
- a:setName(java.lang.String):V
org.jetbrains.jps.model.JpsNamedElementCollection
- org.jetbrains.jps.model.JpsElementCollection
- a:findChild(java.lang.String):org.jetbrains.jps.model.JpsNamedElement
org.jetbrains.jps.model.JpsProject
- org.jetbrains.jps.model.JpsCompositeElement
- org.jetbrains.jps.model.JpsReferenceableElement
@@ -254,6 +257,7 @@ a:org.jetbrains.jps.model.ex.JpsExElementFactory
- a:createCollection(org.jetbrains.jps.model.JpsElementChildRole):org.jetbrains.jps.model.JpsElementCollection
- a:createContainer(org.jetbrains.jps.model.ex.JpsCompositeElementBase):org.jetbrains.jps.model.ex.JpsElementContainerEx
- a:createContainerCopy(org.jetbrains.jps.model.ex.JpsElementContainerEx,org.jetbrains.jps.model.ex.JpsCompositeElementBase):org.jetbrains.jps.model.ex.JpsElementContainerEx
- a:createNamedElementCollection(org.jetbrains.jps.model.JpsElementChildRole):org.jetbrains.jps.model.JpsNamedElementCollection
- s:getInstance():org.jetbrains.jps.model.ex.JpsExElementFactory
a:org.jetbrains.jps.model.ex.JpsNamedCompositeElementBase
- org.jetbrains.jps.model.ex.JpsCompositeElementBase
@@ -262,6 +266,13 @@ a:org.jetbrains.jps.model.ex.JpsNamedCompositeElementBase
- p:<init>(org.jetbrains.jps.model.ex.JpsNamedCompositeElementBase):V
- getName():java.lang.String
- setName(java.lang.String):V
f:org.jetbrains.jps.model.ex.JpsNamedElementCollectionRole
- org.jetbrains.jps.model.ex.JpsElementChildRoleBase
- org.jetbrains.jps.model.JpsElementCreator
- create():org.jetbrains.jps.model.JpsNamedElementCollection
- s:create(org.jetbrains.jps.model.JpsElementChildRole):org.jetbrains.jps.model.ex.JpsNamedElementCollectionRole
- equals(java.lang.Object):Z
- hashCode():I
a:org.jetbrains.jps.model.fileTypes.FileNameMatcherFactory
- <init>():V
- a:createMatcher(java.lang.String):com.intellij.openapi.fileTypes.FileNameMatcher

View File

@@ -0,0 +1,12 @@
package org.jetbrains.jps.model;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface JpsNamedElementCollection<E extends JpsNamedElement> extends JpsElementCollection<E> {
/**
* Returns a child from this collection which {@link JpsNamedElement#getName() name} is equal to {@code name} or {@code null} if there is
* no such element.
*/
@Nullable E findChild(@NotNull String name);
}

View File

@@ -16,9 +16,7 @@
package org.jetbrains.jps.model.ex;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.JpsElementChildRole;
import org.jetbrains.jps.model.JpsElementCollection;
import org.jetbrains.jps.model.*;
import org.jetbrains.jps.service.JpsServiceManager;
public abstract class JpsExElementFactory {
@@ -27,6 +25,8 @@ public abstract class JpsExElementFactory {
}
public abstract <E extends JpsElement> JpsElementCollection<E> createCollection(JpsElementChildRole<E> role);
public abstract <E extends JpsNamedElement> JpsNamedElementCollection<E> createNamedElementCollection(JpsElementChildRole<E> role);
public abstract JpsElementContainerEx createContainer(@NotNull JpsCompositeElementBase<?> parent);

View File

@@ -0,0 +1,37 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.jps.model.ex;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.*;
public final class JpsNamedElementCollectionRole<E extends JpsNamedElement> extends JpsElementChildRoleBase<JpsNamedElementCollection<E>>
implements JpsElementCreator<JpsNamedElementCollection<E>> {
private final JpsElementChildRole<E> myChildRole;
private JpsNamedElementCollectionRole(@NotNull JpsElementChildRole<E> role) {
super("collection of " + role);
myChildRole = role;
}
@Override
public @NotNull JpsNamedElementCollection<E> create() {
return JpsExElementFactory.getInstance().createNamedElementCollection(myChildRole);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
return myChildRole.equals(((JpsNamedElementCollectionRole)o).myChildRole);
}
@Override
public int hashCode() {
return myChildRole.hashCode();
}
public static <E extends JpsNamedElement> JpsNamedElementCollectionRole<E> create(@NotNull JpsElementChildRole<E> role) {
return new JpsNamedElementCollectionRole<>(role);
}
}

View File

@@ -30,7 +30,8 @@ a:org.jetbrains.jps.model.impl.JpsNamedElementReferenceBase
- p:<init>(java.lang.String,org.jetbrains.jps.model.JpsElementReference):V
- p:<init>(org.jetbrains.jps.model.impl.JpsNamedElementReferenceBase):V
- asExternal(org.jetbrains.jps.model.JpsModel):org.jetbrains.jps.model.JpsElementReference
- pa:getCollection(org.jetbrains.jps.model.JpsCompositeElement):org.jetbrains.jps.model.JpsElementCollection
- p:getCollection(org.jetbrains.jps.model.JpsCompositeElement):org.jetbrains.jps.model.JpsElementCollection
- p:getNamedElementCollection(org.jetbrains.jps.model.JpsCompositeElement):org.jetbrains.jps.model.JpsNamedElementCollection
- getParentReference():org.jetbrains.jps.model.JpsElementReference
- resolve():org.jetbrains.jps.model.JpsNamedElement
- pa:resolve(org.jetbrains.jps.model.JpsNamedElement):org.jetbrains.jps.model.JpsNamedElement

View File

@@ -2,12 +2,12 @@
package org.jetbrains.jps.model.artifact.impl;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.ex.JpsElementCollectionRole;
import org.jetbrains.jps.model.ex.JpsElementChildRoleBase;
import org.jetbrains.jps.model.ex.JpsNamedElementCollectionRole;
final class JpsArtifactRole extends JpsElementChildRoleBase<JpsArtifact> {
private static final JpsArtifactRole INSTANCE = new JpsArtifactRole();
public static final JpsElementCollectionRole<JpsArtifact> ARTIFACT_COLLECTION_ROLE = JpsElementCollectionRole.create(INSTANCE);
public static final JpsNamedElementCollectionRole<JpsArtifact> ARTIFACT_COLLECTION_ROLE = JpsNamedElementCollectionRole.create(INSTANCE);
private JpsArtifactRole() {
super("artifact");

View File

@@ -10,7 +10,7 @@ import org.jetbrains.jps.model.ex.JpsElementBase;
import java.util.*;
@ApiStatus.Internal
public final class JpsElementCollectionImpl<E extends JpsElement> extends JpsElementBase<JpsElementCollectionImpl<E>> implements JpsElementCollection<E> {
public class JpsElementCollectionImpl<E extends JpsElement> extends JpsElementBase<JpsElementCollectionImpl<E>> implements JpsElementCollection<E> {
private final List<E> myElements;
private final Map<E, E> myCopyToOriginal;
private final JpsElementChildRole<E> myChildRole;
@@ -21,7 +21,7 @@ public final class JpsElementCollectionImpl<E extends JpsElement> extends JpsEle
myCopyToOriginal = null;
}
private JpsElementCollectionImpl(JpsElementCollectionImpl<E> original) {
protected JpsElementCollectionImpl(JpsElementCollectionImpl<E> original) {
myChildRole = original.myChildRole;
myElements = new ArrayList<>(original.myElements.size());
myCopyToOriginal = new HashMap<>(original.myElements.size());

View File

@@ -17,9 +17,7 @@ package org.jetbrains.jps.model.impl;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.JpsElementChildRole;
import org.jetbrains.jps.model.JpsElementCollection;
import org.jetbrains.jps.model.*;
import org.jetbrains.jps.model.ex.JpsCompositeElementBase;
import org.jetbrains.jps.model.ex.JpsElementContainerEx;
import org.jetbrains.jps.model.ex.JpsElementContainerImpl;
@@ -42,4 +40,9 @@ public final class JpsExElementFactoryImpl extends JpsExElementFactory {
public <E extends JpsElement> JpsElementCollection<E> createCollection(JpsElementChildRole<E> role) {
return new JpsElementCollectionImpl<>(role);
}
@Override
public <E extends JpsNamedElement> JpsNamedElementCollection<E> createNamedElementCollection(JpsElementChildRole<E> role) {
return new JpsNamedElementCollectionImpl<>(role);
}
}

View File

@@ -0,0 +1,64 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.jps.model.impl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsElementChildRole;
import org.jetbrains.jps.model.JpsElementCreator;
import org.jetbrains.jps.model.JpsNamedElement;
import org.jetbrains.jps.model.JpsNamedElementCollection;
import java.util.HashMap;
import java.util.Map;
final class JpsNamedElementCollectionImpl<E extends JpsNamedElement> extends JpsElementCollectionImpl<E> implements
JpsNamedElementCollection<E> {
private final Map<String, E> myElementByName = new HashMap<>();
JpsNamedElementCollectionImpl(JpsElementChildRole<E> role) {
super(role);
}
JpsNamedElementCollectionImpl(JpsNamedElementCollectionImpl<E> original) {
super(original);
for (E element : getElements()) {
myElementByName.put(element.getName(), element);
}
}
@Override
public @Nullable E findChild(@NotNull String name) {
return myElementByName.get(name);
}
@Override
public @NotNull E addChild(@NotNull JpsElementCreator<E> creator) {
E child = super.addChild(creator);
myElementByName.put(child.getName(), child);
return child;
}
@Override
public <X extends E> X addChild(X element) {
X child = super.addChild(element);
myElementByName.put(child.getName(), child);
return child;
}
@Override
public void removeChild(@NotNull E element) {
super.removeChild(element);
myElementByName.remove(element.getName());
}
@Override
public void removeAllChildren() {
super.removeAllChildren();
myElementByName.clear();
}
@Override
public @NotNull JpsElementCollectionImpl<E> createCopy() {
return new JpsNamedElementCollectionImpl<>(this);
}
}

View File

@@ -38,6 +38,11 @@ public abstract class JpsNamedElementReferenceBase<S extends JpsNamedElement, T
JpsElementCollection<? extends S> collection = getCollection(parent);
if (collection == null) return null;
if (collection instanceof JpsNamedElementCollection<?>) {
S element = ((JpsNamedElementCollection<? extends S>)collection).findChild(myElementName);
return element != null ? resolve(element) : null;
}
final List<? extends S> elements = collection.getElements();
for (S element : elements) {
if (element.getName().equals(myElementName)) {
@@ -50,7 +55,18 @@ public abstract class JpsNamedElementReferenceBase<S extends JpsNamedElement, T
return null;
}
protected abstract @Nullable JpsElementCollection<? extends S> getCollection(@NotNull JpsCompositeElement parent);
/**
* @deprecated override {@link #getNamedElementCollection} instead to speed up {@link #resolve()}
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
protected @Nullable JpsElementCollection<? extends S> getCollection(@NotNull JpsCompositeElement parent) {
return getNamedElementCollection(parent);
}
protected @Nullable JpsNamedElementCollection<? extends S> getNamedElementCollection(@NotNull JpsCompositeElement parent) {
return null;
}
protected abstract @Nullable T resolve(S element);

View File

@@ -4,28 +4,50 @@ package org.jetbrains.jps.model.impl;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsCompositeElement;
import org.jetbrains.jps.model.JpsElementCollection;
import org.jetbrains.jps.model.JpsElementReference;
import org.jetbrains.jps.model.JpsNamedElement;
import org.jetbrains.jps.model.*;
import org.jetbrains.jps.model.ex.JpsElementChildRoleBase;
import org.jetbrains.jps.model.ex.JpsElementCollectionRole;
import org.jetbrains.jps.model.ex.JpsNamedElementCollectionRole;
/**
* This class is for internal use only, override {@link JpsNamedElementReferenceBase} instead.
*/
@ApiStatus.Internal
public abstract class JpsNamedElementReferenceImpl<T extends JpsNamedElement, Self extends JpsNamedElementReferenceImpl<T, Self>> extends JpsNamedElementReferenceBase<T, T, Self> {
protected final JpsElementCollectionRole<? extends T> myCollectionRole;
/**
* @deprecated use {@link #getCollectionRole()} instead
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
protected final @Nullable JpsElementCollectionRole<? extends T> myCollectionRole;
private final JpsElementChildRoleBase<? extends JpsElementCollection<? extends T>> myActualCollectionRole;
/**
* @deprecated use {@link #JpsNamedElementReferenceImpl(JpsNamedElementCollectionRole, String, JpsElementReference)} instead JpsNamedElementReferenceImpl}
*/
@Deprecated
protected JpsNamedElementReferenceImpl(@NotNull JpsElementCollectionRole<? extends T> role, @NotNull String elementName,
@NotNull JpsElementReference<? extends JpsCompositeElement> parentReference) {
super(elementName, parentReference);
myCollectionRole = role;
myActualCollectionRole = role;
}
protected JpsNamedElementReferenceImpl(@NotNull JpsNamedElementCollectionRole<? extends T> role, @NotNull String elementName,
@NotNull JpsElementReference<? extends JpsCompositeElement> parentReference) {
super(elementName, parentReference);
myCollectionRole = null;
myActualCollectionRole = role;
}
protected JpsElementChildRoleBase<? extends JpsElementCollection<? extends T>> getCollectionRole() {
return myActualCollectionRole;
}
protected JpsNamedElementReferenceImpl(JpsNamedElementReferenceImpl<T, Self> original) {
super(original);
myCollectionRole = original.myCollectionRole;
myActualCollectionRole = original.myActualCollectionRole;
}
@Override
@@ -35,6 +57,6 @@ public abstract class JpsNamedElementReferenceImpl<T extends JpsNamedElement, Se
@Override
protected @Nullable JpsElementCollection<? extends T> getCollection(@NotNull JpsCompositeElement parent) {
return parent.getContainer().getChild(myCollectionRole);
return parent.getContainer().getChild(myActualCollectionRole);
}
}

View File

@@ -2,12 +2,12 @@
package org.jetbrains.jps.model.library.impl;
import org.jetbrains.jps.model.ex.JpsElementChildRoleBase;
import org.jetbrains.jps.model.ex.JpsElementCollectionRole;
import org.jetbrains.jps.model.ex.JpsNamedElementCollectionRole;
import org.jetbrains.jps.model.library.JpsLibrary;
public final class JpsLibraryRole extends JpsElementChildRoleBase<JpsLibrary> {
private static final JpsLibraryRole INSTANCE = new JpsLibraryRole();
public static final JpsElementCollectionRole<JpsLibrary> LIBRARIES_COLLECTION_ROLE = JpsElementCollectionRole.create(INSTANCE);
public static final JpsNamedElementCollectionRole<JpsLibrary> LIBRARIES_COLLECTION_ROLE = JpsNamedElementCollectionRole.create(INSTANCE);
private JpsLibraryRole() {
super("library");

View File

@@ -3,10 +3,7 @@ package org.jetbrains.jps.model.library.impl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.model.JpsCompositeElement;
import org.jetbrains.jps.model.JpsElement;
import org.jetbrains.jps.model.JpsElementCollection;
import org.jetbrains.jps.model.JpsElementReference;
import org.jetbrains.jps.model.*;
import org.jetbrains.jps.model.impl.JpsNamedElementReferenceBase;
import org.jetbrains.jps.model.library.JpsLibrary;
import org.jetbrains.jps.model.library.JpsTypedLibrary;
@@ -44,7 +41,7 @@ public final class JpsSdkReferenceImpl<P extends JpsElement> extends JpsNamedEle
}
@Override
protected @Nullable JpsElementCollection<? extends JpsLibrary> getCollection(@NotNull JpsCompositeElement parent) {
protected @Nullable JpsNamedElementCollection<? extends JpsLibrary> getNamedElementCollection(@NotNull JpsCompositeElement parent) {
return parent.getContainer().getChild(JpsLibraryRole.LIBRARIES_COLLECTION_ROLE);
}

View File

@@ -3,12 +3,12 @@ package org.jetbrains.jps.model.module.impl;
import org.jetbrains.jps.model.JpsElementChildRole;
import org.jetbrains.jps.model.ex.JpsElementChildRoleBase;
import org.jetbrains.jps.model.ex.JpsElementCollectionRole;
import org.jetbrains.jps.model.ex.JpsNamedElementCollectionRole;
import org.jetbrains.jps.model.module.JpsModule;
public final class JpsModuleRole extends JpsElementChildRoleBase<JpsModule> {
private static final JpsElementChildRole<JpsModule> INSTANCE = new JpsModuleRole();
public static final JpsElementCollectionRole<JpsModule> MODULE_COLLECTION_ROLE = JpsElementCollectionRole.create(INSTANCE);
public static final JpsNamedElementCollectionRole<JpsModule> MODULE_COLLECTION_ROLE = JpsNamedElementCollectionRole.create(INSTANCE);
private JpsModuleRole() {
super("module");