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

Camelcade / Perl5-IDEA / #525521660

24 Aug 2025 01:28PM UTC coverage: 75.89% (-6.3%) from 82.227%
#525521660

push

github

hurricup
Migrated coverage reporting to https://github.com/nbaztec/coveralls-jacoco-gradle-plugin

See: https://github.com/kt3k/coveralls-gradle-plugin/issues/119

14751 of 22639 branches covered (65.16%)

Branch coverage included in aggregate %.

31091 of 37767 relevant lines covered (82.32%)

0.82 hits per line

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

79.58
/plugin/backend/src/main/java/com/perl5/lang/perl/util/PerlSubUtil.java
1
/*
2
 * Copyright 2015-2025 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.util;
18

19
import com.intellij.openapi.project.Project;
20
import com.intellij.openapi.util.Ref;
21
import com.intellij.openapi.util.text.StringUtil;
22
import com.intellij.psi.search.GlobalSearchScope;
23
import com.intellij.psi.stubs.StubIndex;
24
import com.intellij.util.Processor;
25
import com.perl5.lang.perl.psi.*;
26
import com.perl5.lang.perl.psi.references.PerlImplicitDeclarationsService;
27
import com.perl5.lang.perl.psi.stubs.subsdeclarations.PerlSubDeclarationIndex;
28
import com.perl5.lang.perl.psi.stubs.subsdeclarations.PerlSubDeclarationReverseIndex;
29
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlLightSubDefinitionsIndex;
30
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlLightSubDefinitionsReverseIndex;
31
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlSubDefinitionReverseIndex;
32
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlSubDefinitionsIndex;
33
import org.jetbrains.annotations.NotNull;
34
import org.jetbrains.annotations.Nullable;
35

36
import java.util.*;
37

38

39
public final class PerlSubUtil {
40
  private PerlSubUtil() {
41
  }
42

43
  /**
44
   * Searching project files for sub definitions by specific package and function name
45
   *
46
   * @param project       project to search in
47
   * @param canonicalName canonical function name package::name
48
   * @return Collection of found definitions
49
   */
50
  public static Collection<PerlSubDefinitionElement> getSubDefinitions(@NotNull Project project,
51
                                                                       @Nullable String canonicalName) {
52
    return getSubDefinitions(project, canonicalName, GlobalSearchScope.allScope(project));
1✔
53
  }
54

55
  public static Collection<PerlSubDefinitionElement> getSubDefinitions(@NotNull Project project,
56
                                                                       @Nullable String canonicalName,
57
                                                                       @NotNull GlobalSearchScope scope) {
58
    if (canonicalName == null) {
1!
59
      return Collections.emptyList();
×
60
    }
61
    List<PerlSubDefinitionElement> result = new ArrayList<>();
1✔
62
    processSubDefinitions(project, canonicalName, scope, result::add);
1✔
63
    return result;
1✔
64
  }
65

66
  public static Collection<PerlSubDefinitionElement> getSubDefinitionsInPackage(@NotNull Project project,
67
                                                                                @NotNull String packageName) {
68
    return getSubDefinitionsInPackage(project, packageName, GlobalSearchScope.allScope(project));
1✔
69
  }
70

71
  public static Collection<PerlSubDefinitionElement> getSubDefinitionsInPackage(@NotNull Project project,
72
                                                                                @NotNull String packageName,
73
                                                                                @NotNull GlobalSearchScope scope) {
74
    List<PerlSubDefinitionElement> result = new ArrayList<>();
1✔
75
    processSubDefinitionsInPackage(project, packageName, scope, result::add);
1✔
76
    return result;
1✔
77
  }
78

79
  public static boolean processSubDefinitionsInPackage(@NotNull Project project,
80
                                                       @NotNull String packageName,
81
                                                       @NotNull GlobalSearchScope scope,
82
                                                       @NotNull Processor<? super PerlSubDefinitionElement> processor) {
83
    return PerlImplicitDeclarationsService.getInstance(project).processSubsInPackage(packageName, processor) &&
1!
84
           PerlSubDefinitionReverseIndex.getInstance().processElements(project, packageName, scope, processor) &&
1!
85
           PerlLightSubDefinitionsReverseIndex.getInstance().processLightElements(project, packageName, scope, processor);
1!
86
  }
87

88
  public static boolean processSubDeclarationsInPackage(@NotNull Project project,
89
                                                        @NotNull String packageName,
90
                                                        @NotNull GlobalSearchScope scope,
91
                                                        @NotNull Processor<? super PerlSubDeclarationElement> processor) {
92
    return PerlSubDeclarationReverseIndex.getInstance().processElements(project, packageName, scope, processor);
1✔
93
  }
94

95
  public static boolean processSubDefinitions(@NotNull Project project,
96
                                              @NotNull String canonicalName,
97
                                              @NotNull GlobalSearchScope scope,
98
                                              @NotNull Processor<? super PerlSubDefinitionElement> processor) {
99
    return PerlImplicitDeclarationsService.getInstance(project).processSubs(canonicalName, processor) &&
1!
100
           PerlSubDefinitionsIndex.getInstance().processElements(project, canonicalName, scope, processor) &&
1✔
101
           PerlLightSubDefinitionsIndex.getInstance().processLightElements(project, canonicalName, scope, processor);
1✔
102
  }
103

104
  public static boolean processSubDeclarations(@NotNull Project project,
105
                                               @NotNull String canonicalName,
106
                                               @NotNull GlobalSearchScope scope,
107
                                               @NotNull Processor<? super PerlSubDeclarationElement> processor) {
108
    return PerlSubDeclarationIndex.getInstance().processElements(project, canonicalName, scope, processor);
1✔
109
  }
110

111

112
  /**
113
   * Returns list of defined subs names
114
   *
115
   * @param project project to search in
116
   * @return collection of sub names
117
   */
118
  public static Collection<String> getDefinedSubsNames(Project project) {
119
    // fixme honor scope
120
    Collection<String> result = PerlSubDefinitionsIndex.getInstance().getAllNames(project);
1✔
121
    result.addAll(PerlLightSubDefinitionsIndex.getInstance().getAllNames(project));
1✔
122
    return result;
1✔
123
  }
124

125
  /**
126
   * Searching project files for sub declarations by specific package and function name
127
   *
128
   * @param project       project to search in
129
   * @param canonicalName canonical function name package::name
130
   * @return Collection of found definitions
131
   */
132
  public static Collection<PerlSubDeclarationElement> getSubDeclarations(Project project, String canonicalName) {
133
    return getSubDeclarations(project, canonicalName, GlobalSearchScope.allScope(project));
1✔
134
  }
135

136
  public static Collection<PerlSubDeclarationElement> getSubDeclarations(Project project, String canonicalName, GlobalSearchScope scope) {
137
    if (canonicalName == null) {
1!
138
      return Collections.emptyList();
×
139
    }
140
    return StubIndex.getElements(PerlSubDeclarationIndex.KEY, canonicalName, project, scope, PerlSubDeclarationElement.class);
1✔
141
  }
142

143

144
  public static @NotNull List<PerlSubElement> collectOverridingSubs(PerlSubElement subBase) {
145
    return collectOverridingSubs(subBase, new HashSet<>());
1✔
146
  }
147

148
  public static @NotNull List<PerlSubElement> collectOverridingSubs(@NotNull PerlSubElement subElement,
149
                                                                    @NotNull Set<? super String> recursionSet) {
150
    List<PerlSubElement> result;
151
    result = new ArrayList<>();
1✔
152
    for (PerlSubElement directDescendant : getDirectOverridingSubs(subElement)) {
1✔
153
      String packageName = directDescendant.getNamespaceName();
1✔
154
      if (StringUtil.isNotEmpty(packageName) && !recursionSet.contains(packageName)) {
1!
155
        recursionSet.add(packageName);
1✔
156
        result.add(directDescendant);
1✔
157
        result.addAll(collectOverridingSubs(directDescendant, recursionSet));
1✔
158
      }
159
    }
1✔
160

161
    return result;
1!
162
  }
163

164
  public static boolean processRelatedSubsInPackage(@NotNull Project project,
165
                                                    @NotNull GlobalSearchScope searchScope,
166
                                                    @NotNull String packageName,
167
                                                    @NotNull Processor<? super PerlCallableElement> processor) {
168
    return processSubDefinitionsInPackage(project, packageName, searchScope, processor) &&
1!
169
           processSubDeclarationsInPackage(project, packageName, searchScope, processor);
1!
170
  }
171

172
  public static @Nullable PerlSubElement getDirectSuperMethod(@NotNull PerlSubElement subElement) {
173

174
    if (!subElement.isMethod()) {
1!
175
      return null;
×
176
    }
177

178
    Ref<PerlSubElement> resultRef = Ref.create();
1✔
179
    PerlMroUtil.processCallables(
1✔
180
      subElement.getProject(), subElement.getResolveScope(), subElement.getNamespaceName(), Collections.singleton(subElement.getSubName()),
1✔
181
      true,
182
      it -> {
183
        if (it instanceof PerlSubElement subElement1) {
1!
184
          resultRef.set(subElement1);
1✔
185
          return false;
1✔
186
        }
187
        return true;
×
188
      },
189
      true);
190

191
    return resultRef.get();
1✔
192
  }
193

194
  public static @NotNull PerlSubElement getTopmostSuperMethod(PerlSubElement subElement) {
195
    Set<String> classRecursion = new HashSet<>();
1✔
196

197
    PerlSubElement run = subElement;
1✔
198
    while (true) {
199
      String packageName = run.getNamespaceName();
1✔
200
      if (StringUtil.isEmpty(packageName) || classRecursion.contains(packageName)) {
1!
201
        return run;
×
202
      }
203
      classRecursion.add(packageName);
1✔
204
      PerlSubElement newRun = getDirectSuperMethod(run);
1✔
205
      if (newRun == null) {
1✔
206
        return run;
1!
207
      }
208
      run = newRun;
1✔
209
    }
1✔
210
  }
211

212
  public static List<PerlSubDefinitionElement> getDirectOverridingSubs(@NotNull PerlSubElement subElement) {
213
    List<PerlSubDefinitionElement> result = new ArrayList<>();
1✔
214
    processDirectOverridingSubs(subElement, (Processor<? super PerlSubDefinitionElement>)result::add);
1✔
215
    return result;
1✔
216
  }
217

218
  @SuppressWarnings({"UnusedReturnValue", "SameReturnValue"})
219
  public static boolean processDirectOverridingSubs(@NotNull PerlSubElement subElement,
220
                                                    @NotNull Processor<? super PerlSubDefinitionElement> processor) {
221
    String packageName = subElement.getNamespaceName();
1✔
222
    String subName = subElement.getSubName();
1✔
223
    if (packageName == null || subName == null) {
1!
224
      return true;
×
225
    }
226
    Set<String> recursionSet = new HashSet<>();
1✔
227
    Project project = subElement.getProject();
1✔
228
    Queue<String> packagesToProcess = new ArrayDeque<>(5);
1✔
229
    packagesToProcess.add(packageName);
1✔
230

231
    while (!packagesToProcess.isEmpty()) {
1✔
232
      packageName = packagesToProcess.poll();
1✔
233
      NAMESPACE:
234
      for (PerlNamespaceDefinitionElement childNamespace : PerlPackageUtil.getChildNamespaces(project, packageName)) {
1✔
235
        String childNamespaceName = childNamespace.getNamespaceName();
1✔
236
        if (StringUtil.isNotEmpty(childNamespaceName) && recursionSet.add(childNamespaceName)) {
1!
237
          for (PerlSubDefinitionElement subDefinition : PerlSubUtil.getSubDefinitionsInPackage(project, childNamespaceName)) {
1✔
238
            if (subName.equals(subDefinition.getSubName()) && getDirectSuperMethod(subDefinition) == subElement) {
1!
239
              processor.process(subDefinition);
1✔
240
              continue NAMESPACE;
1✔
241
            }
242
          }
1✔
243
          packagesToProcess.add(childNamespaceName);
1✔
244
        }
245
      }
1✔
246
    }
247
    return true;
1✔
248
  }
249
}
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