• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Camelcade / Perl5-IDEA / #525521805

30 Mar 2026 07:53AM UTC coverage: 75.96% (-0.02%) from 75.979%
#525521805

Pull #3191

github

web-flow
Merge 700b7aaae into 1a7865f21
Pull Request #3191: Cleaned up several unused methods

14761 of 22624 branches covered (65.24%)

Branch coverage included in aggregate %.

31077 of 37721 relevant lines covered (82.39%)

0.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.32
/plugin/backend/src/main/java/com/perl5/lang/perl/idea/project/PerlNamesBackendCache.java
1
/*
2
 * Copyright 2015-2026 Alexandr Evstigneev
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 * http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16

17
package com.perl5.lang.perl.idea.project;
18

19
import com.intellij.ide.lightEdit.LightEdit;
20
import com.intellij.openapi.Disposable;
21
import com.intellij.openapi.application.ApplicationManager;
22
import com.intellij.openapi.application.ReadAction;
23
import com.intellij.openapi.application.WriteAction;
24
import com.intellij.openapi.diagnostic.Logger;
25
import com.intellij.openapi.progress.ProgressManager;
26
import com.intellij.openapi.project.DumbService;
27
import com.intellij.openapi.project.Project;
28
import com.intellij.openapi.roots.ModuleRootEvent;
29
import com.intellij.openapi.roots.ModuleRootListener;
30
import com.intellij.psi.PsiManager;
31
import com.intellij.psi.PsiTreeChangeAdapter;
32
import com.intellij.psi.PsiTreeChangeEvent;
33
import com.intellij.psi.impl.source.resolve.ResolveCache;
34
import com.intellij.util.concurrency.AppExecutorUtil;
35
import com.intellij.util.messages.MessageBusConnection;
36
import com.intellij.util.ui.update.MergingUpdateQueue;
37
import com.intellij.util.ui.update.Update;
38
import com.perl5.lang.perl.psi.stubs.namespaces.PerlLightNamespaceIndex;
39
import com.perl5.lang.perl.psi.stubs.namespaces.PerlNamespaceIndex;
40
import com.perl5.lang.perl.psi.stubs.subsdeclarations.PerlSubDeclarationIndex;
41
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlLightSubDefinitionsIndex;
42
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlSubDefinitionsIndex;
43
import com.perl5.lang.perl.util.PerlPackageUtilCore;
44
import com.perl5.lang.perl.util.PerlTimeLogger;
45
import kotlin.Unit;
46
import kotlin.jvm.functions.Function0;
47
import org.jetbrains.annotations.NotNull;
48
import org.jetbrains.annotations.Nullable;
49
import org.jetbrains.annotations.TestOnly;
50
import org.jspecify.annotations.NonNull;
51

52
import java.util.*;
53
import java.util.concurrent.ConcurrentLinkedQueue;
54
import java.util.concurrent.atomic.AtomicBoolean;
55

56

57
public class PerlNamesBackendCache implements PerlNamesCache {
58
  private static final Logger LOG = Logger.getInstance(PerlNamesBackendCache.class);
1✔
59
  private final MergingUpdateQueue myQueue = new MergingUpdateQueue("Perl names cache updater", 1000, true, null, this, null, false);
1✔
60
  private final Project myProject;
61
  private volatile Set<String> myKnownSubs = Collections.emptySet();
1✔
62
  private volatile Set<String> myKnownNamespaces = Collections.emptySet();
1✔
63
  private final AtomicBoolean myIsDisposed = new AtomicBoolean(false);
1✔
64
  private @Nullable Disposable myTestDisposable = null;
1✔
65
  private final Queue<Function0<Unit>> myPendingCallbacks = new ConcurrentLinkedQueue<>();
1✔
66

67
  public PerlNamesBackendCache(Project project) {
1✔
68
    myProject = project;
1✔
69
    if (LightEdit.owns(myProject) || project.isDefault()) {
1!
70
      return;
×
71
    }
72
    MessageBusConnection connection = project.getMessageBus().connect(this);
1✔
73
    connection.subscribe(ModuleRootListener.TOPIC, new ModuleRootListener() {
1✔
74
      @Override
75
      public void rootsChanged(@NotNull ModuleRootEvent event) {
76
        queueUpdate();
1✔
77
      }
1✔
78
    });
79
    connection.subscribe(DumbService.DUMB_MODE, new DumbService.DumbModeListener() {
1✔
80
      @Override
81
      public void exitDumbMode() {
82
        queueUpdate();
1✔
83
      }
1✔
84
    });
85
    PsiManager.getInstance(myProject).addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
1✔
86
      @Override
87
      public void childAdded(@NotNull PsiTreeChangeEvent event) {
88
        queueUpdate();
1✔
89
      }
1✔
90

91
      @Override
92
      public void childRemoved(@NotNull PsiTreeChangeEvent event) {
93
        queueUpdate();
1✔
94
      }
1✔
95

96
      @Override
97
      public void childReplaced(@NotNull PsiTreeChangeEvent event) {
98
        queueUpdate();
1✔
99
      }
1✔
100

101
      @Override
102
      public void childMoved(@NotNull PsiTreeChangeEvent event) {
103
        queueUpdate();
×
104
      }
×
105

106
      @Override
107
      public void childrenChanged(@NotNull PsiTreeChangeEvent event) {
108
        queueUpdate();
1✔
109
      }
1✔
110

111
      @Override
112
      public void propertyChanged(@NotNull PsiTreeChangeEvent event) {
113
        queueUpdate();
1✔
114
      }
1✔
115
    }, this);
116
  }
1✔
117

118
  private void queueUpdate() {
119
    if (!myProject.isDefault()) {
1!
120
      myQueue.queue(Update.create(this, () -> doUpdateCache(() -> Unit.INSTANCE)));
1✔
121
    }
122
  }
1✔
123

124
  private void doUpdateCache(kotlin.jvm.functions.@NonNull Function0<kotlin.Unit> callback) {
125
    if (myProject.isDefault() || LightEdit.owns(myProject)) {
1!
126
      return;
×
127
    }
128
    myPendingCallbacks.add(callback);
1✔
129
    var updateNbra = ReadAction.nonBlocking(() -> {
1✔
130
      PerlTimeLogger logger = PerlTimeLogger.create(LOG);
1✔
131
      logger.debug("Starting to update names cache at");
1✔
132

133
      PerlSubDeclarationIndex subDeclarationIndex = PerlSubDeclarationIndex.getInstance();
1✔
134
      Collection<String> declarationsNames = subDeclarationIndex.getAllNames(myProject);
1✔
135
      Set<String> subsSet = new HashSet<>(declarationsNames);
1✔
136
      logger.debug("Got declarations names: ", declarationsNames.size());
1✔
137
      ProgressManager.checkCanceled();
1✔
138

139
      PerlSubDefinitionsIndex subDefinitionsIndex = PerlSubDefinitionsIndex.getInstance();
1✔
140
      Collection<String> definitionsNames = subDefinitionsIndex.getAllNames(myProject);
1✔
141
      subsSet.addAll(definitionsNames);
1✔
142
      logger.debug("Got definitions names: ", definitionsNames.size());
1✔
143
      ProgressManager.checkCanceled();
1✔
144

145
      PerlLightSubDefinitionsIndex lightSubDefinitionsIndex = PerlLightSubDefinitionsIndex.getInstance();
1✔
146
      Collection<String> lightDefinitionsNames = lightSubDefinitionsIndex.getAllNames(myProject);
1✔
147
      subsSet.addAll(lightDefinitionsNames);
1✔
148
      logger.debug("Got light definitions names: ", lightDefinitionsNames.size());
1✔
149
      ProgressManager.checkCanceled();
1✔
150
      var newSubSet = Collections.unmodifiableSet(subsSet);
1✔
151
      if (!newSubSet.equals(myKnownSubs)) {
1✔
152
        myKnownSubs = newSubSet;
1✔
153
        ResolveCache.getInstance(myProject).clearCache(true);
1✔
154
      }
155

156
      Set<String> namespacesSet = new HashSet<>(PerlPackageUtilCore.CORE_PACKAGES_ALL);
1✔
157

158
      PerlNamespaceIndex namespaceIndex = PerlNamespaceIndex.getInstance();
1✔
159
      Collection<String> namespacesNames = namespaceIndex.getAllNames(myProject);
1✔
160
      namespacesSet.addAll(namespacesNames);
1✔
161
      logger.debug("Got namespaces names: ", namespacesNames.size());
1✔
162
      ProgressManager.checkCanceled();
1✔
163

164
      PerlLightNamespaceIndex lightNamespaceIndex = PerlLightNamespaceIndex.getInstance();
1✔
165
      Collection<String> lightNamespacesNames = lightNamespaceIndex.getAllNames(myProject);
1✔
166
      namespacesSet.addAll(lightNamespacesNames);
1✔
167
      logger.debug("Got light namespaces names: ", lightNamespacesNames.size());
1✔
168
      var newNamespaceSet = Collections.unmodifiableSet(namespacesSet);
1✔
169
      if (!newNamespaceSet.equals(myKnownNamespaces)) {
1✔
170
        myKnownNamespaces = newNamespaceSet;
1✔
171
        ResolveCache.getInstance(myProject).clearCache(true);
1✔
172
      }
173

174
      logger.debug("Names cache updated");
1✔
175

176
        Function0<kotlin.Unit> pending;
177
        while ((pending = myPendingCallbacks.poll()) != null) {
1✔
178
          pending.invoke();
1✔
179
        }
180
      //noinspection ReturnOfNull
181
      return null;
1✔
182
      }).inSmartMode(myProject)
1✔
183
      .expireWith(this)
1✔
184
      .coalesceBy(this);
1✔
185

186
    if (myTestDisposable != null) {
1✔
187
      updateNbra = updateNbra.expireWith(myTestDisposable);
1✔
188
    }
189

190
    updateNbra.submit(AppExecutorUtil.getAppExecutorService());
1✔
191
  }
1✔
192

193
  @Override
194
  public boolean isDisposed() {
195
    return myIsDisposed.get();
×
196
  }
197

198
  @Override
199
  public void forceCacheUpdate(kotlin.jvm.functions.@NonNull Function0<kotlin.Unit> callback) {
200
    var application = ApplicationManager.getApplication();
1✔
201
    if (application.isDispatchThread()) {
1✔
202
      application.executeOnPooledThread(() -> doUpdateCache(callback));
1✔
203
    }
204
    else {
205
      doUpdateCache(callback);
1✔
206
    }
207
  }
1✔
208

209
  @Override
210
  @TestOnly
211
  public void cleanCache() {
212
    myKnownSubs = Collections.emptySet();
1✔
213
    myKnownNamespaces = Collections.emptySet();
1✔
214
  }
1✔
215

216
  @Override
217
  public void dispose() {
218
    WriteAction.run(() -> myIsDisposed.set(true));
1✔
219
  }
1✔
220

221
  @Override
222
  public @NotNull Set<String> getSubsNamesSet() {
223
    return myKnownSubs;
1!
224
  }
225

226
  @Override
227
  public @NotNull Set<String> getNamespacesNamesSet() {
228
    return myKnownNamespaces;
1!
229
  }
230

231
  @TestOnly
232
  public void setTestDisposable(@NotNull Disposable disposable) {
233
    myTestDisposable = disposable;
1✔
234
  }
1✔
235
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc