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

Camelcade / Perl5-IDEA / #525521635

20 Jul 2025 03:45PM UTC coverage: 82.266% (-0.09%) from 82.355%
#525521635

push

github

hurricup
Build 252.23892.248

30936 of 37605 relevant lines covered (82.27%)

0.82 hits per line

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

92.68
/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.lexer.PerlElementTypes;
26
import com.perl5.lang.perl.psi.*;
27
import com.perl5.lang.perl.psi.references.PerlImplicitDeclarationsService;
28
import com.perl5.lang.perl.psi.stubs.subsdeclarations.PerlSubDeclarationIndex;
29
import com.perl5.lang.perl.psi.stubs.subsdeclarations.PerlSubDeclarationReverseIndex;
30
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlLightSubDefinitionsIndex;
31
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlLightSubDefinitionsReverseIndex;
32
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlSubDefinitionReverseIndex;
33
import com.perl5.lang.perl.psi.stubs.subsdefinitions.PerlSubDefinitionsIndex;
34
import org.jetbrains.annotations.NotNull;
35
import org.jetbrains.annotations.Nullable;
36

37
import java.util.*;
38

39

40
public final class PerlSubUtil implements PerlElementTypes {
41
  private PerlSubUtil() {
42
  }
43

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

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

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

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

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

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

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

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

112

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

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

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

144

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

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

162
    return result;
1✔
163
  }
164

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

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

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

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

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

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

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

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

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

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