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

Camelcade / Perl5-IDEA / #525521628

13 Jul 2025 04:11PM UTC coverage: 82.308% (-0.07%) from 82.38%
#525521628

push

github

hurricup
#2842 #3039 Moved values deserialization to helper class

Fixes #3039

47 of 49 new or added lines in 37 files covered. (95.92%)

120 existing lines in 32 files now uncovered.

30868 of 37503 relevant lines covered (82.31%)

0.82 hits per line

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

93.26
/plugin/backend/src/main/java/com/perl5/lang/perl/psi/utils/PerlVariableAnnotations.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.psi.utils;
18

19
import com.intellij.psi.PsiElement;
20
import com.intellij.psi.stubs.StubInputStream;
21
import com.intellij.psi.stubs.StubOutputStream;
22
import com.intellij.psi.util.*;
23
import com.intellij.util.Processor;
24
import com.intellij.util.containers.ContainerUtil;
25
import com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValue;
26
import com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValueSerializer;
27
import com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValuesManager;
28
import com.perl5.lang.perl.lexer.PerlTokenSetsEx;
29
import com.perl5.lang.perl.parser.PerlElementTypesGenerated;
30
import com.perl5.lang.perl.psi.*;
31
import org.jetbrains.annotations.NotNull;
32

33
import java.io.IOException;
34
import java.util.List;
35

36
import static com.perl5.lang.perl.idea.codeInsight.typeInference.value.PerlValues.UNKNOWN_VALUE;
37

38
public class PerlVariableAnnotations {
39
  private static final PerlVariableAnnotations EMPTY = new PerlVariableAnnotations() {
1✔
40
    @Override
41
    public void setIsDeprecated() {
UNCOV
42
      throw new UnsupportedOperationException();
×
43
    }
44

45
    @Override
46
    public void setValue(@NotNull PerlValue value) {
UNCOV
47
      throw new UnsupportedOperationException();
×
48
    }
49

50
    @Override
51
    public boolean isEmpty() {
52
      return true;
1✔
53
    }
54
  };
55

56
  private static final byte IS_DEPRECATED = 0x01;
57

58
  private byte myFlags = 0;
1✔
59

60
  private @NotNull PerlValue myValue = UNKNOWN_VALUE;
1✔
61

62
  private PerlVariableAnnotations() {
1✔
63
  }
1✔
64

65
  private PerlVariableAnnotations(byte flags, @NotNull PerlValue value) {
1✔
66
    myFlags = flags;
1✔
67
    myValue = value;
1✔
68
  }
1✔
69

70
  public void serialize(@NotNull StubOutputStream dataStream) throws IOException {
71
    dataStream.writeByte(myFlags);
1✔
72
    PerlValueSerializer.serialize(myValue, dataStream);
1✔
73
  }
1✔
74

75
  public boolean isDeprecated() {
76
    return (myFlags & IS_DEPRECATED) == IS_DEPRECATED;
1✔
77
  }
78

79
  public void setIsDeprecated() {
80
    myFlags |= IS_DEPRECATED;
1✔
81
  }
1✔
82

83
  public @NotNull PerlValue getAnnotatedValue() {
84
    return myValue;
1✔
85
  }
86

87
  public void setValue(@NotNull PerlValue value) {
88
    myValue = value;
1✔
89
  }
1✔
90

91
  public boolean isEmpty() {
92
    return myFlags == 0 && myValue.isUnknown();
1✔
93
  }
94

95
  public static PerlVariableAnnotations empty() {
96
    return EMPTY;
1✔
97
  }
98

99
  public static PerlVariableAnnotations deserialize(@NotNull StubInputStream dataStream) throws IOException {
100
    return new PerlVariableAnnotations(
1✔
101
      dataStream.readByte(),
1✔
102
      PerlValuesManager.readValue(dataStream)
1✔
103
    );
104
  }
105

106
  public static @NotNull PerlVariableAnnotations from(@NotNull PerlVariableDeclarationElement variableDeclarationElement) {
107
    PerlVariableAnnotations annotations = new PerlVariableAnnotations();
1✔
108
    processAnnotations(variableDeclarationElement, new VariableAnnotationProcessor() {
1✔
109
      @Override
110
      public boolean processDeprecated() {
111
        annotations.setIsDeprecated();
1✔
112
        return true;
1✔
113
      }
114

115
      @Override
116
      public boolean processType(@NotNull PerlAnnotationType annotationType) {
117
        annotations.setValue(annotationType.getValue());
1✔
118
        return true;
1✔
119
      }
120
    });
121
    return annotations.isEmpty() ? EMPTY : annotations;
1✔
122
  }
123

124
  private static @NotNull List<PerlAnnotation> collectAnnotationsInScope(@NotNull PerlVariableDeclarationElement variableDeclarationElement) {
125
    return CachedValuesManager.getCachedValue(variableDeclarationElement, () -> {
1✔
126
      List<PerlAnnotation> perlAnnotations = PerlAnnotations.collectAnnotations(variableDeclarationElement);
1✔
127
      var declarationExpression = variableDeclarationElement.getDeclarationExpression();
1✔
128
      if (perlAnnotations.isEmpty() && declarationExpression != null) {
1✔
129
        perlAnnotations = PerlAnnotations.collectAnnotations(declarationExpression);
1✔
130
      }
131
      if (perlAnnotations.isEmpty() && declarationExpression != null &&
1✔
132
          PsiUtilCore.getElementType(declarationExpression.getParent()) == PerlElementTypesGenerated.FOREACH_ITERATOR) {
1✔
133
        perlAnnotations =
1✔
134
          PerlAnnotations.collectAnnotations(PsiTreeUtil.getParentOfType(variableDeclarationElement, PerlForeachCompound.class));
1✔
135
      }
136
      if (perlAnnotations.isEmpty() &&
1✔
137
          PsiUtilCore.getElementType(variableDeclarationElement.getParent()) == PerlElementTypesGenerated.SIGNATURE_ELEMENT) {
1✔
138
        perlAnnotations = ContainerUtil.filter(
1✔
139
          PerlAnnotations.collectAnnotations(PsiTreeUtil.getParentOfType(variableDeclarationElement, PerlSubElement.class)),
1✔
140
          it -> !(it instanceof PsiPerlAnnotationDeprecated));
1✔
141
      }
142
      return CachedValueProvider.Result.create(perlAnnotations, PsiModificationTracker.MODIFICATION_COUNT);
1✔
143
    });
144
  }
145

146
  public static boolean processAnnotations(@NotNull PerlVariableDeclarationElement variableDeclarationElement,
147
                                           @NotNull PerlVariableAnnotations.VariableAnnotationProcessor annotationsProcessor) {
148

149
    var annotationList = collectAnnotationsInScope(variableDeclarationElement);
1✔
150
    if (annotationList.isEmpty()) {
1✔
151
      return true;
1✔
152
    }
153
    boolean valueSet = false;
1✔
154
    boolean valueSetExplicitly = false;
1✔
155
    for (PerlAnnotation annotation : annotationList) {
1✔
156
      if (annotation instanceof PsiPerlAnnotationDeprecated) {
1✔
157
        if (!annotationsProcessor.processDeprecated()) {
1✔
UNCOV
158
          return false;
×
159
        }
160
      }
161
      else if (!valueSetExplicitly && annotation instanceof PerlAnnotationType typeAnnotation &&
1✔
162
               typeAnnotation.accept(variableDeclarationElement.getVariable())) {
1✔
163
        var isWildCard = typeAnnotation.isWildCard();
1✔
164
        if (!valueSet || !isWildCard) {
1✔
165
          valueSet = true;
1✔
166
          valueSetExplicitly = !isWildCard;
1✔
167
          if (!annotationsProcessor.processType(typeAnnotation)) {
1✔
168
            return false;
1✔
169
          }
170
        }
171
      }
172
    }
1✔
173
    return true;
1✔
174
  }
175

176
  @Override
177
  public String toString() {
178
    return isEmpty() ? "none" : "PerlVariableAnnotations{" +
1✔
179
                                "myFlags=" + myFlags +
180
                                ", myValue=" + myValue +
181
                                '}';
1✔
182
  }
183

184
  /**
185
   * Processes variable declarations to which {@code typeAnnotation} may belong
186
   */
187
  public static boolean processPotentialTargets(@NotNull PerlAnnotationType typeAnnotation,
188
                                                @NotNull Processor<? super PerlVariableDeclarationElement> declarationElementProcessor) {
189
    PsiElement run = typeAnnotation.getAnnotationContainer();
1✔
190
    while (run != null && PerlTokenSetsEx.getWHITE_SPACE_AND_REAL_COMMENTS().contains(PsiUtilCore.getElementType(run))) {
1✔
191
      run = run.getNextSibling();
1✔
192
    }
193

194
    if (run instanceof PerlForeachCompound foreachCompound) {
1✔
195
      run = foreachCompound.getForeachIterator();
1✔
196
    }
197
    else if (run instanceof PerlSubElement subElement) {
1✔
198
      run = subElement.getSignatureContent();
1✔
199
    }
200
    else if (!(run instanceof PsiPerlExpr || run instanceof PsiPerlStatement || run instanceof PsiPerlVariableDeclarationElement)) {
1✔
201
      return true;
1✔
202
    }
203

204
    if (run == null) {
1✔
205
      return true;
1✔
206
    }
207

208
    var visitor = new PerlRecursiveVisitor() {
1✔
209
      @Override
210
      public void visitVariableDeclarationElement(@NotNull PsiPerlVariableDeclarationElement o) {
211
        if (!declarationElementProcessor.process(o)) {
1✔
UNCOV
212
          stop();
×
213
        }
214
      }
1✔
215

216
      @Override
217
      public void visitBlock(@NotNull PsiPerlBlock o) {
218
        // do not enter blocks
219
      }
1✔
220
    };
221
    run.accept(visitor);
1✔
222

223
    return !visitor.isStopped();
1✔
224
  }
225

226
  public interface VariableAnnotationProcessor {
227
    @SuppressWarnings("SameReturnValue")
228
    default boolean processDeprecated() {
UNCOV
229
      return true;
×
230
    }
231

232
    default boolean processType(@NotNull PerlAnnotationType annotationType) {
UNCOV
233
      return true;
×
234
    }
235
  }
236
}
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