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

wurstscript / WurstScript / 209

25 Oct 2023 11:42AM CUT coverage: 63.746% (-0.01%) from 63.756%
209

Pull #1081

circleci

Frotty
WIP
Pull Request #1081: More performance improvements

17267 of 27087 relevant lines covered (63.75%)

0.64 hits per line

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

93.49
de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/attributes/names/NameResolution.java
1
package de.peeeq.wurstscript.attributes.names;
2

3
import com.google.common.collect.ImmutableCollection;
4
import com.google.common.collect.ImmutableList;
5
import com.google.common.collect.Lists;
6
import de.peeeq.wurstscript.ast.*;
7
import de.peeeq.wurstscript.jassIm.ImExpr;
8
import de.peeeq.wurstscript.jassIm.ImFunction;
9
import de.peeeq.wurstscript.jassIm.JassIm;
10
import de.peeeq.wurstscript.translation.imtranslation.ImTranslator;
11
import de.peeeq.wurstscript.types.*;
12
import de.peeeq.wurstscript.utils.Utils;
13
import org.eclipse.jdt.annotation.Nullable;
14

15
import java.util.ArrayList;
16
import java.util.List;
17
import java.util.Optional;
18

19
public class NameResolution {
×
20

21
    public static ImmutableCollection<FuncLink> lookupFuncsNoConfig(Element node, String name, boolean showErrors) {
22
        StructureDef nearestStructureDef = node.attrNearestStructureDef();
1✔
23
        if (nearestStructureDef != null) {
1✔
24
            // inside a class one can write foo instead of this.foo()
25
            // so the receiver type is implicitly given by the enclosing class
26
            WurstType receiverType = nearestStructureDef.attrTyp();
1✔
27
            ImmutableCollection<FuncLink> funcs = node.lookupMemberFuncs(receiverType, name, showErrors);
1✔
28
            if (!funcs.isEmpty()) {
1✔
29
                return funcs;
1✔
30
            }
31
        }
32

33

34
        List<FuncLink> result = Lists.newArrayList();
1✔
35
        WScope scope = node.attrNearestScope();
1✔
36
        while (scope != null) {
1✔
37
            for (DefLink n : scope.attrNameLinks().get(name)) {
1✔
38
                if (n instanceof FuncLink && n.getReceiverType() == null) {
1✔
39
                    if (!result.contains(n)) {
1✔
40
                        result.add((FuncLink) n);
1✔
41
                    }
42
                }
43
            }
1✔
44
            scope = nextScope(scope);
1✔
45
        }
46
        return removeDuplicates(result);
1✔
47
    }
48

49
    public static ImmutableCollection<FuncLink> lookupFuncs(Element e, String name, boolean showErrors) {
50
        ArrayList<FuncLink> result = Lists.newArrayList(e.lookupFuncsNoConfig(name, showErrors));
1✔
51
        for (int i = 0; i < result.size(); i++) {
1✔
52
            result.set(i, result.get(i).withConfigDef());
1✔
53
        }
54
        return ImmutableList.copyOf(result);
1✔
55
    }
56

57
    private static <T extends NameLink> ImmutableCollection<T> removeDuplicates(List<T> nameLinks) {
58
        List<T> result = Lists.newArrayList();
1✔
59
        nextLink:
60
        for (T nl : nameLinks) {
1✔
61
            for (T other : result) {
1✔
62
                if (other.getDef() == nl.getDef()) {
1✔
63
                    continue nextLink;
1✔
64
                }
65
            }
1✔
66
            result.add(nl);
1✔
67
        }
1✔
68
        return ImmutableList.copyOf(result);
1✔
69
    }
70

71
    private static @Nullable WScope nextScope(WScope scope) {
72
        Element parent = scope.getParent();
1✔
73
        if (parent == null) {
1✔
74
            return null;
1✔
75
        }
76
        WScope currentScope = scope;
1✔
77
        if (currentScope instanceof ModuleInstanciation) {
1✔
78
            ModuleInstanciation moduleInstanciation = (ModuleInstanciation) currentScope;
1✔
79
            // for module instanciations the next scope is the package in which
80
            // the module was defined
81
            return nextScope(moduleInstanciation.attrModuleOrigin());
1✔
82
        }
83
        return parent.attrNearestScope();
1✔
84
    }
85

86
    public static ImmutableCollection<FuncLink> lookupMemberFuncs(Element node, WurstType receiverType, String name, boolean showErrors) {
87
        List<FuncLink> result = Lists.newArrayList();
1✔
88
        addMemberMethods(node, receiverType, name, result);
1✔
89

90
        WScope scope = node.attrNearestScope();
1✔
91
        while (scope != null) {
1✔
92
            for (DefLink n : scope.attrNameLinks().get(name)) {
1✔
93
                if (!(n instanceof FuncLink)) {
1✔
94
                    continue;
1✔
95
                }
96
                DefLink n2 = matchDefLinkReceiver(n, receiverType, node, false);
1✔
97
                if (n2 != null) {
1✔
98
                    FuncLink f = (FuncLink) n2;
1✔
99
                    result.add(f);
1✔
100
                }
101
            }
1✔
102
            scope = nextScope(scope);
1✔
103
        }
104
        return removeDuplicates(result);
1✔
105
    }
106

107
    public static void addMemberMethods(Element node,
108
                                        WurstType receiverType, String name, List<FuncLink> result) {
109
        receiverType.addMemberMethods(node, name, result);
1✔
110
    }
1✔
111

112
    public static NameLink lookupVarNoConfig(Element node, String name, boolean showErrors) {
113
        NameLink privateCandidate = null;
1✔
114
        List<NameLink> candidates = Lists.newArrayList();
1✔
115

116
        for (WScope scope = node.attrNearestScope(); scope != null; scope = nextScope(scope)) {
1✔
117

118
            if (scope instanceof LoopStatementWithVarDef) {
1✔
119
                LoopStatementWithVarDef loop = (LoopStatementWithVarDef) scope;
1✔
120
                // only consider this scope if node is in the body:
121
                if (!Utils.elementContained(Optional.of(node), loop.getBody())) {
1✔
122
                    continue;
1✔
123
                }
124
            }
125

126
            if (scope instanceof StructureDef) {
1✔
127
                StructureDef nearestStructureDef = (StructureDef) scope;
1✔
128
                // inside a class one can write foo instead of this.foo()
129
                // so the receiver type is implicitly given by the enclosing class
130
                WurstTypeNamedScope receiverType = (WurstTypeNamedScope) nearestStructureDef.attrTyp();
1✔
131
                for (DefLink link : receiverType.nameLinks(name)) {
1✔
132
                    if (!(link instanceof FuncLink)) {
1✔
133
                        return link;
1✔
134
                    }
135
                }
1✔
136
            }
137
            for (DefLink n : scope.attrNameLinks().get(name)) {
1✔
138
                WurstType n_receiverType = n.getReceiverType();
1✔
139
                if (n instanceof VarLink && n_receiverType == null) {
1✔
140

141
                    if (n.getVisibility() != Visibility.PRIVATE_OTHER
1✔
142
                            && n.getVisibility() != Visibility.PROTECTED_OTHER) {
1✔
143
                        candidates.add(n);
1✔
144
                    } else if (privateCandidate == null) {
1✔
145
                        privateCandidate = n;
1✔
146
                    }
147

148
                } else if (n instanceof TypeDefLink) {
1✔
149
                    candidates.add(n);
1✔
150
                }
151

152
            }
1✔
153
            if (candidates.size() > 0) {
1✔
154
                if (showErrors && candidates.size() > 1) {
1✔
155
                    node.addError("Reference to variable " + name + " is ambiguous. Alternatives are:\n"
1✔
156
                            + Utils.printAlternatives(candidates));
1✔
157
                }
158
                return candidates.get(0);
1✔
159
            }
160
        }
161
        if (showErrors) {
1✔
162
            if (privateCandidate == null) {
1✔
163
                node.addError("Could not find variable " + name + ".");
×
164
            } else {
165
                node.addError(Utils.printElementWithSource(Optional.of(privateCandidate.getDef()))
×
166
                        + " is not visible inside this package. If you want to access it, declare it public.");
167
                return privateCandidate;
×
168
            }
169
        }
170
        return null;
1✔
171
    }
172

173
    public static NameLink lookupMemberVar(Element node, WurstType receiverType, String name, boolean showErrors) {
174
        WScope scope = node.attrNearestScope();
1✔
175
        while (scope != null) {
1✔
176
            for (DefLink n : scope.attrNameLinks().get(name)) {
1✔
177
                if (!(n instanceof VarLink)) {
1✔
178
                    continue;
1✔
179
                }
180
                DefLink n2 = matchDefLinkReceiver(n, receiverType, node, showErrors);
1✔
181
                if (n2 != null) {
1✔
182
                    return n2;
1✔
183
                }
184
            }
1✔
185
            scope = nextScope(scope);
1✔
186
        }
187

188
        if (receiverType instanceof WurstTypeClassOrInterface) {
1✔
189
            WurstTypeClassOrInterface ct = (WurstTypeClassOrInterface) receiverType;
1✔
190
            for (DefLink n : ct.nameLinks().get(name)) {
1✔
191
                if (n instanceof VarLink || n instanceof TypeDefLink) {
1✔
192
                    if (n.getVisibility().isPublic()) {
1✔
193
                        return n;
1✔
194
                    }
195
                }
196
            }
×
197
        } else if (receiverType instanceof WurstTypeArray && name.equals("length")) {
1✔
198
            // special lookup for length
199
            WurstTypeArray wta = (WurstTypeArray) receiverType;
1✔
200
            if (wta.getDimensions() > 0) {
1✔
201
                int size = wta.getSize(0);
1✔
202
                return new OtherLink(Visibility.PUBLIC, name, WurstTypeInt.instance()) {
1✔
203
                    @Override
204
                    public ImExpr translate(NameRef e, ImTranslator t, ImFunction f) {
205
                        return JassIm.ImIntVal(size);
1✔
206
                    }
207
                };
208
            }
209
        }
210

211
        return null;
1✔
212
    }
213

214
    public static DefLink matchDefLinkReceiver(DefLink n, WurstType receiverType, Element node, boolean showErrors) {
215
        WurstType n_receiverType = n.getReceiverType();
1✔
216
        if (n_receiverType == null) {
1✔
217
            return null;
1✔
218
        }
219
        VariableBinding mapping = receiverType.matchAgainstSupertype(n_receiverType, node, VariableBinding.emptyMapping().withTypeVariables(n.getTypeParams()), VariablePosition.RIGHT);
1✔
220
        if (mapping == null) {
1✔
221
            return null;
1✔
222
        }
223
        if (showErrors) {
1✔
224
            if (n.getVisibility() == Visibility.PRIVATE_OTHER) {
1✔
225
                node.addError(Utils.printElement(n.getDef()) + " is private and cannot be used here.");
×
226
            } else if (n.getVisibility() == Visibility.PROTECTED_OTHER) {
1✔
227
                node.addError(Utils.printElement(n.getDef()) + " is protected and cannot be used here.");
×
228
            }
229
        }
230
        return n.withTypeArgBinding(node, mapping);
1✔
231
    }
232

233
    public static @Nullable TypeDef lookupType(Element node, String name, boolean showErrors) {
234

235
        NameLink privateCandidate = null;
1✔
236
        List<NameLink> candidates = Lists.newArrayList();
1✔
237

238
        WScope scope = node.attrNearestScope();
1✔
239
        while (scope != null) {
1✔
240
            for (NameLink n : scope.attrTypeNameLinks().get(name)) {
1✔
241
                if (n.getDef() instanceof TypeDef) {
1✔
242
                    if (n.getVisibility() != Visibility.PRIVATE_OTHER
1✔
243
                            && n.getVisibility() != Visibility.PROTECTED_OTHER) {
1✔
244
                        candidates.add(n);
1✔
245
                    } else if (privateCandidate == null) {
1✔
246
                        privateCandidate = n;
1✔
247
                    }
248
                }
249
            }
1✔
250
            if (candidates.size() > 0) {
1✔
251
                if (showErrors && candidates.size() > 1) {
1✔
252
                    node.addError("Reference to type " + name + " is ambiguous. Alternatives are:\n"
×
253
                            + Utils.printAlternatives(candidates));
×
254
                }
255
                return (TypeDef) candidates.get(0).getDef();
1✔
256
            }
257
            scope = nextScope(scope);
1✔
258
        }
259
        if (showErrors) {
1✔
260
            if (privateCandidate == null) {
1✔
261
                node.addError("Could not find type " + name + ".");
1✔
262
            } else {
263
                node.addError(Utils.printElementWithSource(Optional.of(privateCandidate.getDef()))
1✔
264
                        + " is not visible inside this package. If you want to access it, declare it public.");
265
                return (TypeDef) privateCandidate.getDef();
1✔
266
            }
267
        }
268
        return null;
1✔
269
    }
270

271
    public static PackageLink lookupPackage(Element node, String name, boolean showErrors) {
272
        WScope scope = node.attrNearestScope();
1✔
273
        while (scope != null) {
1✔
274
            for (NameLink n : scope.attrNameLinks().get(name)) {
1✔
275
                if (n instanceof PackageLink) {
1✔
276
                    return (PackageLink) n;
1✔
277
                }
278
            }
×
279
            scope = nextScope(scope);
1✔
280
        }
281
        return null;
1✔
282
    }
283

284
    public static ImmutableCollection<FuncLink> lookupFuncsShort(Element elem, String name) {
285
        return lookupFuncs(elem, name, true);
1✔
286
    }
287

288
    public static ImmutableCollection<FuncLink> lookupMemberFuncsShort(Element elem, WurstType receiverType, String name) {
289
        return lookupMemberFuncs(elem, receiverType, name, true);
1✔
290
    }
291

292
    public static NameLink lookupVarShort(Element node, String name) {
293
        return lookupVar(node, name, true);
×
294
    }
295

296
    public static NameLink lookupMemberVarShort(Element node, WurstType receiverType, String name) {
297
        return lookupMemberVar(node, receiverType, name, true);
1✔
298
    }
299

300
    public static @Nullable TypeDef lookupTypeShort(Element node, String name) {
301
        return lookupType(node, name, true);
1✔
302
    }
303

304
    public static PackageLink lookupPackageShort(Element node, String name) {
305
        return lookupPackage(node, name, true);
1✔
306
    }
307

308
    public static NameLink lookupVar(Element e, String name, boolean showErrors) {
309
        NameLink v = e.lookupVarNoConfig(name, showErrors);
1✔
310
        if (v != null) {
1✔
311
            NameDef actual = v.getDef().attrConfigActualNameDef();
1✔
312
            return v.withDef(actual);
1✔
313
        }
314
        return null;
1✔
315
    }
316

317

318
}
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

© 2025 Coveralls, Inc