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

Camelcade / Perl5-IDEA / #525521557

29 May 2025 01:55PM UTC coverage: 82.275% (+0.001%) from 82.274%
#525521557

push

github

hurricup
Migrated to ProjectActivity

0 of 1 new or added line in 1 file covered. (0.0%)

104 existing lines in 12 files now uncovered.

30882 of 37535 relevant lines covered (82.28%)

0.82 hits per line

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

87.07
/plugin/core/src/main/java/com/perl5/lang/perl/idea/completion/util/PerlSubCompletionUtil.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.idea.completion.util;
18

19
import com.intellij.codeInsight.lookup.LookupElementBuilder;
20
import com.intellij.openapi.util.text.StringUtil;
21
import com.intellij.psi.PsiElement;
22
import com.intellij.psi.PsiFile;
23
import com.intellij.psi.PsiNamedElement;
24
import com.intellij.psi.PsiReference;
25
import com.intellij.psi.util.PsiTreeUtil;
26
import com.perl5.lang.perl.extensions.packageprocessor.PerlExportDescriptor;
27
import com.perl5.lang.perl.idea.codeInsight.typeInference.value.*;
28
import com.perl5.lang.perl.idea.completion.inserthandlers.SubSelectionHandler;
29
import com.perl5.lang.perl.idea.completion.providers.processors.PerlCompletionProcessor;
30
import com.perl5.lang.perl.idea.completion.providers.processors.PerlSimpleCompletionProcessor;
31
import com.perl5.lang.perl.idea.completion.providers.processors.PerlSimpleDelegatingCompletionProcessor;
32
import com.perl5.lang.perl.idea.completion.providers.processors.PerlVariableCompletionProcessor;
33
import com.perl5.lang.perl.psi.*;
34
import com.perl5.lang.perl.psi.impl.PerlImplicitSubDefinition;
35
import com.perl5.lang.perl.psi.references.PerlImplicitDeclarationsService;
36
import com.perl5.lang.perl.util.PerlPackageUtil;
37
import org.jetbrains.annotations.NotNull;
38
import org.jetbrains.annotations.Nullable;
39

40
import java.util.Collections;
41
import java.util.HashSet;
42
import java.util.Set;
43

44

45
public class PerlSubCompletionUtil {
×
46
  public static final SubSelectionHandler SUB_SELECTION_HANDLER = new SubSelectionHandler();
1✔
47

48

49
  public static boolean processSubDefinitionLookupElement(@NotNull PerlSubDefinitionElement subDefinition,
50
                                                          @NotNull PerlCompletionProcessor completionProcessor) {
51
    return processSubDefinitionLookupElement(subDefinition, null, completionProcessor);
1✔
52
  }
53

54
  public static boolean processSubDefinitionLookupElement(@NotNull PerlSubDefinitionElement subDefinition,
55
                                                          @Nullable PerlExportDescriptor exportDescriptor,
56
                                                          @NotNull PerlCompletionProcessor completionProcessor) {
57
    return processSubDefinitionLookupElement(
1✔
58
      exportDescriptor == null ? subDefinition.getSubName() : exportDescriptor.getImportedName(),
1✔
59
      subDefinition, completionProcessor);
60
  }
61

62
  public static boolean processSubDefinitionLookupElement(@NotNull String nameToUse,
63
                                                          @NotNull PerlSubDefinitionElement subDefinition,
64
                                                          @NotNull PerlCompletionProcessor completionProcessor) {
65
    if (!completionProcessor.matches(nameToUse)) {
1✔
66
      return completionProcessor.result();
1✔
67
    }
68
    LookupElementBuilder newElement = LookupElementBuilder
1✔
69
      .create(subDefinition, nameToUse)
1✔
70
      .withIcon(subDefinition.getIcon(0))
1✔
71
      .withStrikeoutness(subDefinition.isDeprecated())
1✔
72
      .withTypeText(subDefinition.getNamespaceName(), true);
1✔
73

74
    String argsString = subDefinition.getSubArgumentsListAsString();
1✔
75

76
    if (!argsString.isEmpty()) {
1✔
77
      newElement = newElement
1✔
78
        .withInsertHandler(SUB_SELECTION_HANDLER)
1✔
79
        .withTailText(argsString);
1✔
80
    }
81

82
    return completionProcessor.process(newElement);
1✔
83
  }
84

85
  public static boolean processImportedEntityLookupElement(@NotNull PsiElement element,
86
                                                           @NotNull PerlExportDescriptor exportDescriptor,
87
                                                           @NotNull PerlCompletionProcessor completionProcessor) {
88
    return switch (element) {
1✔
89
      case PerlSubDefinitionElement subDefinitionElement ->
1✔
90
        processSubDefinitionLookupElement(subDefinitionElement, exportDescriptor, completionProcessor);
1✔
91
      case PerlSubDeclarationElement subDeclarationElement ->
1✔
92
        processSubDeclarationLookupElement(subDeclarationElement, exportDescriptor, completionProcessor);
1✔
93
      case PerlGlobVariableElement globVariableElement ->
×
94
        processGlobLookupElement(globVariableElement, exportDescriptor, completionProcessor);
×
95
      default -> throw new RuntimeException("Don't know how to make lookup element for " + element.getClass());
×
96
    };
97
  }
98

99
  public static boolean processSubDeclarationLookupElement(@NotNull PerlSubDeclarationElement subDeclaration,
100
                                                           @NotNull PerlCompletionProcessor completionProcessor) {
101
    return processSubDeclarationLookupElement(subDeclaration, null, completionProcessor);
1✔
102
  }
103

104
  public static boolean processSubDeclarationLookupElement(@NotNull PerlSubDeclarationElement subDeclaration,
105
                                                           @Nullable PerlExportDescriptor exportDescriptor,
106
                                                           @NotNull PerlCompletionProcessor completionProcessor) {
107

108
    String lookupString = exportDescriptor == null ? subDeclaration.getSubName() : exportDescriptor.getImportedName();
1✔
109
    if (!completionProcessor.matches(lookupString)) {
1✔
110
      return completionProcessor.result();
×
111
    }
112

113
    return completionProcessor.process(LookupElementBuilder
1✔
114
                                         .create(subDeclaration, lookupString)
1✔
115
                                         .withIcon(subDeclaration.getIcon(0))
1✔
116
                                         .withStrikeoutness(subDeclaration.isDeprecated())
1✔
117
                                         .withInsertHandler(SUB_SELECTION_HANDLER)
1✔
118
                                         .withTypeText(subDeclaration.getNamespaceName(), true)
1✔
119
    );
120
  }
121

122
  public static boolean processGlobLookupElement(@NotNull PerlGlobVariableElement globVariable,
123
                                                 @NotNull PerlCompletionProcessor completionProcessor) {
124
    return processGlobLookupElement(globVariable, null, completionProcessor);
1✔
125
  }
126

127
  /**
128
   * Probably duplicate of {@link PerlVariableCompletionUtil#processVariableLookupElement(PerlGlobVariableElement, boolean, PerlVariableCompletionProcessor)}
129
   */
130
  public static boolean processGlobLookupElement(@NotNull PerlGlobVariableElement globVariable,
131
                                                 @Nullable PerlExportDescriptor exportDescriptor,
132
                                                 @NotNull PerlCompletionProcessor completionProcessor) {
133
    String lookupString = exportDescriptor == null ? globVariable.getName() : exportDescriptor.getImportedName();
1✔
134
    if (!completionProcessor.matches(lookupString)) {
1✔
135
      return completionProcessor.result();
×
136
    }
137

138
    return completionProcessor.process(LookupElementBuilder
1✔
139
                                         .create(globVariable, StringUtil.notNullize(lookupString))
1✔
140
                                         .withIcon(globVariable.getIcon(0))
1✔
141
                                         .withInsertHandler(SUB_SELECTION_HANDLER)
1✔
142
                                         .withTypeText(globVariable.getNamespaceName(), true)
1✔
143
    );
144
  }
145

146
  @SuppressWarnings("UnusedReturnValue")
147
  public static boolean processUnresolvedSubsLookups(@NotNull PerlSubElement subDefinition,
148
                                                     @NotNull PerlCompletionProcessor completionProcessor) {
149
    final String packageName = subDefinition.getNamespaceName();
1✔
150
    if (packageName == null) {
1✔
151
      return completionProcessor.result();
×
152
    }
153

154
    final Set<String> namesSet = new HashSet<>();
1✔
155
    PsiFile containingFile = subDefinition.getContainingFile();
1✔
156
    containingFile.accept(new PerlCompletionRecursiveVisitor(completionProcessor) {
1✔
157
      @Override
158
      protected boolean shouldVisitLightElements() {
159
        return true;
1✔
160
      }
161

162
      @Override
163
      public void visitMethod(@NotNull PsiPerlMethod method) {
164
        doVisitMethod(method);
1✔
165
        super.visitMethod(method);
1✔
166
      }
1✔
167

168
      private void doVisitMethod(@NotNull PsiPerlMethod method) {
169
        PerlCallValue methodValue = PerlCallValue.from(method);
1✔
170
        if (methodValue == null) {
1✔
171
          return;
×
172
        }
173

174
        PerlValue namespaceValue = methodValue.getNamespaceNameValue();
1✔
175

176
        if (!namespaceValue.canRepresentNamespace(packageName)) {
1✔
177
          return;
×
178
        }
179
        PerlSubNameElement subNameElement = method.getSubNameElement();
1✔
180

181
        if (subNameElement == null || !subNameElement.isValid()) {
1✔
182
          return;
×
183
        }
184

185
        String subName = subNameElement.getName();
1✔
186

187
        if (StringUtil.isEmpty(subName) || namesSet.contains(subName) || !completionProcessor.matches(subName)) {
1✔
188
          return;
×
189
        }
190
        PsiReference[] references = subNameElement.getReferences();
1✔
191
        if (references.length == 0) {
1✔
192
          return;
×
193
        }
194

195
        for (PsiReference reference : references) {
1✔
196
          if (reference.resolve() != null) {
1✔
197
            return;
1✔
198
          }
199
        }
200
        // unresolved
201
        namesSet.add(subName);
1✔
202
        completionProcessor.process(LookupElementBuilder.create(subName));
1✔
203
      }
1✔
204
    });
205
    return completionProcessor.result();
1✔
206
  }
207

208
  public static void processWithNotOverriddenSubs(@NotNull PerlSubElement subDefinition,
209
                                                  @NotNull PerlCompletionProcessor completionProcessor) {
210
    PerlPackageUtil.processNotOverridedMethods(
1✔
211
      PsiTreeUtil.getParentOfType(subDefinition, PerlNamespaceDefinitionElement.class),
1✔
212
      subDefinitionBase -> {
213
        String lookupString = subDefinitionBase.getSubName();
1✔
214
        if (completionProcessor.matches(lookupString)) {
1✔
215
          return completionProcessor.process(LookupElementBuilder.create(subDefinitionBase, lookupString));
1✔
216
        }
217
        return completionProcessor.result();
×
218
      }
219
    );
220
  }
1✔
221

222
  public static boolean processSubsCompletionsForCallValue(@NotNull PerlSimpleCompletionProcessor completionProcessor,
223
                                                           @NotNull PerlCallValue perlValue,
224
                                                           boolean isStatic) {
225
    return perlValue.processTargetNamespaceElements(
1✔
226
      completionProcessor.getLeafElement(), new PerlNamespaceItemProcessor<>() {
1✔
227
        @Override
228
        public boolean processItem(@NotNull PsiNamedElement element) {
229
          return switch (element) {
1✔
230
            case PerlImplicitSubDefinition implicitSubDefinition
1✔
231
              when implicitSubDefinition.isAnonymous() -> //noinspection DuplicateBranchesInSwitch
1✔
UNCOV
232
              completionProcessor.result();
×
233
            case PerlSubDefinitionElement subDefinitionElement
1✔
234
              when !subDefinitionElement.isAnonymous() &&
1✔
235
                   (isStatic && subDefinitionElement.isStatic() || subDefinitionElement.isMethod()) ->
1✔
236
              processSubDefinitionLookupElement(subDefinitionElement, completionProcessor);
1✔
237
            case PerlSubDeclarationElement subDeclarationElement
1✔
238
              when (isStatic && subDeclarationElement.isStatic() || subDeclarationElement.isMethod()) ->
1✔
239
              processSubDeclarationLookupElement(subDeclarationElement, completionProcessor);
1✔
240
            case PerlGlobVariableElement perlGlobVariableElement
1✔
241
              when perlGlobVariableElement.isLeftSideOfAssignment() && StringUtil.isNotEmpty(element.getName()) ->
1✔
242
              processGlobLookupElement(perlGlobVariableElement, completionProcessor);
1✔
243
            default -> completionProcessor.result();
1✔
244
          };
245
        }
246

247
        @Override
248
        public boolean processImportedItem(@NotNull PsiNamedElement element,
249
                                           @NotNull PerlExportDescriptor exportDescriptor) {
250
          return processImportedEntityLookupElement(element, exportDescriptor, completionProcessor);
1✔
251
        }
252

253
        @Override
254
        public boolean processOrphanDescriptor(@NotNull PerlExportDescriptor exportDescriptor) {
255
          if (exportDescriptor.isSub()) {
1✔
256
            return exportDescriptor.processLookupElement(completionProcessor);
1✔
257
          }
258
          return completionProcessor.result();
1✔
259
        }
260
      });
261
  }
262

263
  public static boolean processBuiltInSubsLookupElements(PerlSimpleCompletionProcessor completionProcessor) {
264
    PerlCompletionProcessor builtInCompletionProcessor = new PerlSimpleDelegatingCompletionProcessor(completionProcessor) {
1✔
265
      @Override
266
      public void addElement(@NotNull LookupElementBuilder lookupElement) {
267
        super.addElement(lookupElement.withBoldness(true));
1✔
268
      }
1✔
269
    };
270

271
    return PerlImplicitDeclarationsService.getInstance(completionProcessor.getProject()).processSubs(
1✔
272
      sub -> sub.isBuiltIn() ? processSubDefinitionLookupElement(sub, builtInCompletionProcessor)
1✔
273
                             : builtInCompletionProcessor.result());
1✔
274
  }
275

276
  /**
277
   * Processes all subs applicable at current context. Declarations, imports, built-ins.
278
   */
279
  @SuppressWarnings("UnusedReturnValue")
280
  public static boolean processContextSubsLookupElements(@NotNull PerlSimpleCompletionProcessor completionProcessor) {
281
    if (!PerlSubCompletionUtil.processBuiltInSubsLookupElements(completionProcessor)) {
1✔
UNCOV
282
      return false;
×
283
    }
284
    PerlCallStaticValue callValue = new PerlCallStaticValue(
1✔
285
      PerlPackageUtil.getContextType(completionProcessor.getLeafElement()), PerlScalarValue.create("dummy"), Collections.emptyList(),
1✔
286
      false);
287
    return processSubsCompletionsForCallValue(completionProcessor, callValue, true);
1✔
288
  }
289
}
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