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

moosetechnology / VerveineJ / 29406151200

15 Jul 2026 09:53AM UTC coverage: 52.68% (-0.04%) from 52.722%
29406151200

push

github

web-flow
Merge pull request #270 from moosetechnology/end-visit-abstractType

correcting a ClassCastException with visiting subtypes of AbstractTypeDeclaration

2023 of 4012 branches covered (50.42%)

Branch coverage included in aggregate %.

7 of 16 new or added lines in 1 file covered. (43.75%)

14 existing lines in 1 file now uncovered.

4484 of 8340 relevant lines covered (53.76%)

2.22 hits per line

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

89.23
/app/src/main/java/fr/inria/verveine/extractor/java/visitors/GetVisitedEntityAbstractVisitor.java
1
package fr.inria.verveine.extractor.java.visitors;
2

3
import fr.inria.verveine.extractor.java.EntityDictionary;
4
import fr.inria.verveine.extractor.java.VerveineJOptions;
5
import fr.inria.verveine.extractor.java.utils.EntityStack;
6
import fr.inria.verveine.extractor.java.utils.StubBinding;
7
import fr.inria.verveine.extractor.java.utils.Util;
8
import org.eclipse.jdt.core.dom.*;
9
import org.eclipse.jdt.core.dom.Initializer;
10
import org.moosetechnology.model.famix.famixjavaentities.*;
11
import org.moosetechnology.model.famix.famixjavaentities.Exception;
12
import org.moosetechnology.model.famix.famixjavaentities.Package;
13
import org.moosetechnology.model.famix.famixjavaentities.Type;
14
import org.moosetechnology.model.famix.famixtraits.TType;
15
import org.moosetechnology.model.famix.famixtraits.TWithMethods;
16
import org.moosetechnology.model.famix.famixtraits.TWithTypes;
17

18
import java.util.ArrayList;
19
import java.util.Collection;
20
import java.util.List;
21
import java.util.Stack;
22

23
/**
24
 * This visitor offers methods to recover FamixEntities from the main JDT Entities and may put them in the context Stack<br>
25
 * To avoid confusion with the ASTVisitor defaults visit(...) methods, and to simplify the choice of using them or not in each subclass,
26
 * the recovering methods here are named after the visited entities: visit(CompilationUnit node) becomes visitCompilationUnit(CompilationUnit node).
27
 */
28
public abstract class GetVisitedEntityAbstractVisitor extends ASTVisitor {
29

30
        /**
31
         * The options that control the behavior of the parser
32
         */
33
        protected VerveineJOptions options;
34

35
        /**
36
         * A stack that keeps the current definition context (package/class/method)
37
         */
38
        protected EntityStack context;
39

40
        /** 
41
         * A dictionary allowing to recover created FAMIX Entities
42
         */
43
        protected EntityDictionary dico;
44

45
        /**
46
         * The super type of an anonymous declaration is only available (without resorting to bindings) when 
47
         * we are in its parent node: a ClassInstanceCreation.
48
         * So we must keep this type from the visit(ClassInstanceCreation) to be used in visit(AnonymousClassDeclaration).<br>
49
         * Note that in some special cases one can also have an anonymous class definition without specifying its superclass.
50
         */
51
        protected Stack<String> anonymousSuperTypeName;
52

53
        public GetVisitedEntityAbstractVisitor(EntityDictionary dico, VerveineJOptions options) {
54
                super();
2✔
55
                this.dico = dico;
3✔
56
                this.options = options;
3✔
57
                this.context = new EntityStack();
5✔
58
                this.anonymousSuperTypeName = new Stack<>();
5✔
59
        }
1✔
60

61
        // a generic visit method for node lists
62
    protected void visitNodeList(List<ASTNode> list) {
63
        for (ASTNode child : list) {
10✔
64
            child.accept(this);
3✔
65
        }
1✔
66
    }
1✔
67

68
        // two visit methods never used
69

70
        @Override
71
        public boolean visit(PackageDeclaration node) {
72
                return false; // no need to visit children of the declaration
2✔
73
        }
74

75
        @Override
76
        public boolean visit(ImportDeclaration node) {
77
                return false; // no need to visit children of the declaration        
2✔
78
        }
79

80
        // CompilationUnit --> FamixNamespace
81

82
        protected Package visitCompilationUnit(CompilationUnit node) {
83
                Package fmx;
84
                PackageDeclaration pckg = node.getPackage();
3✔
85
                if (pckg == null) {
2✔
86
                        fmx = dico.getFamixPackageDefault();
5✔
87
                } else {
88
                        fmx = (Package) dico.getEntityByKey(pckg.resolveBinding());
7✔
89
                }
90
                this.context.pushPckg(fmx);
4✔
91

92
                return fmx;
2✔
93
        }
94

95
        protected void endVisitCompilationUnit(CompilationUnit node) {
96
                this.context.popPckg();
4✔
97
                super.endVisit(node);
3✔
98
        }
1✔
99
        
100
        // type (class/interface) --> FamixClass
101

102
        /*
103
         * Can only be a class or interface declaration
104
         * Local type: see comment of visit(ClassInstanceCreation node)
105
         */
106
        protected TType visitTypeDeclaration(AbstractTypeDeclaration node) {
107
                ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
108
                TType fmx;
109
                if(bnd.isInterface()) {
3✔
110
                        fmx = dico.getFamixInterface(bnd, node.getName().getIdentifier(), (ContainerEntity) /*owner*/context.top());
13✔
111
                } else if (dico.isThrowable(bnd)) {
5✔
112
                        fmx = dico.getFamixException(bnd, node.getName().getIdentifier(), (TWithTypes) /*owner*/context.top());
13✔
113
                } else {
114
                        fmx = dico.getFamixClass(bnd, node.getName().getIdentifier(), /*owner*/context.top());
11✔
115
                }
116
                if (fmx != null) {
2!
117
                        this.context.pushType(fmx);
4✔
118
                }
119
                return fmx;
2✔
120
        }
121

122
        protected void endVisitTypeDeclaration(AnnotationTypeDeclaration node) {
NEW
123
                this.endVisitAbstractTypeDeclaration(node);
×
NEW
124
                super.endVisit(node);
×
NEW
125
        }
×
126

127
        protected void endVisitTypeDeclaration(EnumDeclaration node) {
NEW
128
                this.endVisitAbstractTypeDeclaration(node);
×
NEW
129
                super.endVisit(node);
×
NEW
130
        }
×
131

132
        protected void endVisitTypeDeclaration(ImplicitTypeDeclaration node) {
NEW
133
                this.endVisitAbstractTypeDeclaration(node);
×
NEW
134
                super.endVisit(node);
×
NEW
135
        }
×
136

137
        protected void endVisitTypeDeclaration(RecordDeclaration node) {
138
                this.endVisitAbstractTypeDeclaration(node);
3✔
139
                super.endVisit(node);
3✔
140
        }
1✔
141

142
        protected void endVisitTypeDeclaration(TypeDeclaration node) {
143
                this.endVisitAbstractTypeDeclaration(node);
3✔
144
                super.endVisit(node);
3✔
145
        }
1✔
146

147
        protected void endVisitAbstractTypeDeclaration(AbstractTypeDeclaration node) {
148
                if (context.top() instanceof Type) {
5!
149
                        context.pop();
4✔
150
                }
151
        }
1✔
152

153
        /**
154
         * Creation of an instance of an anonymous class, ie. <code>new AnonymousClassDeclaration</code><br>
155
         * See also field {@link #anonymousSuperTypeName}
156
         * 
157
         * The 'push' possibly done here gets undone in endVisitAnonymousClassDeclaration()
158
         */
159
        protected void possiblyAnonymousClassDeclaration(ClassInstanceCreation node) {
160
                if (node.getAnonymousClassDeclaration() != null) {
3✔
161
                        anonymousSuperTypeName.push(Util.jdtTypeName(node.getType()));
7✔
162
                }
163
        }
1✔
164

165
        /**
166
         * The body of an anonymous class declaration appears within a ClassInstanceCreation<br>
167
         * See also field {@link GetVisitedEntityAbstractVisitor#anonymousSuperTypeName}
168
         */
169
        protected org.moosetechnology.model.famix.famixjavaentities.Class visitAnonymousClassDeclaration(AnonymousClassDeclaration node) {
170
                org.moosetechnology.model.famix.famixjavaentities.Class fmx;
171

172
                ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
173

174
                fmx = this.dico.getFamixClass(bnd, Util.stringForAnonymousName(getAnonymousSuperTypeName(), context), /*owner*/(ContainerEntity) context.top());
14✔
175
                if (fmx != null) {
2!
176
                        this.context.pushType(fmx);
4✔
177
                }
178
                return fmx;
2✔
179
        }
180

181
        protected void endVisitAnonymousClassDeclaration(AnonymousClassDeclaration node) {
182
                if (context.top() instanceof org.moosetechnology.model.famix.famixjavaentities.Class) {
5✔
183
                        context.pop();
4✔
184
                }
185
                if (!anonymousSuperTypeName.empty()) {
4✔
186
                        anonymousSuperTypeName.pop();
4✔
187
                }
188
        }
1✔
189

190
        protected org.moosetechnology.model.famix.famixjavaentities.Enum visitEnumDeclaration(EnumDeclaration node) {
191
                ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
192

193
                org.moosetechnology.model.famix.famixjavaentities.Enum fmx = dico.getFamixEnum(bnd, node.getName().getIdentifier(), (TWithTypes) context.top());
12✔
194
                if (fmx != null) {
2!
195
                        this.context.pushType(fmx);
4✔
196
                }
197
                return fmx;
2✔
198
        }
199

200
        protected void endVisitEnumDeclaration(EnumDeclaration node) {
201
                if (context.top() instanceof org.moosetechnology.model.famix.famixjavaentities.Enum) {
5✔
202
                        this.context.popType();
4✔
203
                }
204
                super.endVisit(node);
3✔
205
        }
1✔
206

207
        protected AnnotationType visitAnnotationTypeDeclaration(AnnotationTypeDeclaration node) {
208
        ITypeBinding bnd = (ITypeBinding) StubBinding.getDeclarationBinding(node);
4✔
209

210
                AnnotationType fmx = dico.getFamixAnnotationType(bnd, node.getName().getIdentifier(), (ContainerEntity) context.top());
12✔
211
                if (fmx != null) {
2!
212
                        context.pushType(fmx);
4✔
213
                }
214
                return fmx;
2✔
215
        }
216

217
        protected void endVisitAnnotationTypeDeclaration(AnnotationTypeDeclaration node) {
218
                if (context.topType() instanceof AnnotationType) {
5!
219
                        context.pop();
4✔
220
                }
221
                super.endVisit(node);
3✔
222
        }
1✔
223

224
        @SuppressWarnings("unchecked")
225
        protected Method visitMethodDeclaration(MethodDeclaration node) {
226
                //System.err.println("visitMethodDeclaration(): " + node.getName().getIdentifier());
227
                IMethodBinding bnd = (IMethodBinding) StubBinding.getDeclarationBinding(node);
4✔
228

229
                Collection<String> paramTypes = new ArrayList<>();
4✔
230
                for (SingleVariableDeclaration param : (List<SingleVariableDeclaration>) node.parameters()) {
11✔
231
                        paramTypes.add(Util.jdtTypeName(param.getType()));
6✔
232
                }
1✔
233

234
                Method fmx = dico.ensureFamixMethod(bnd, node.getName().getIdentifier(), paramTypes, /*returnType*/null, (TWithMethods) /*owner*/context.topType(), EntityDictionary.UNKNOWN_MODIFIERS);
15✔
235

236
                context.pushMethod(fmx);  // whether fmx==null or not
4✔
237
                return fmx;
2✔
238
        }
239

240
        protected void endVisitMethodDeclaration(MethodDeclaration node) {
241
                context.popMethod();
4✔
242
                super.endVisit(node);
3✔
243
        }
1✔
244

245
        /**
246
         * BodyDeclaration ::=
247
         *                [ ... ]
248
         *                 FieldDeclaration
249
         *                 Initializer
250
         *                 MethodDeclaration (for methods and constructors)
251
         * Initializer ::=
252
         *      [ static ] Block
253
         */
254
        public org.moosetechnology.model.famix.famixjavaentities.Initializer visitInitializer(Initializer node) {
255
                return ctxtPushInitializerMethod(Modifier.isStatic(node.getModifiers()), true);
9✔
256
        }
257

258
        public void endVisitInitializer(Initializer node) {
259
                if ( (context.top() instanceof org.moosetechnology.model.famix.famixjavaentities.Initializer) ) {
5!
260
                        this.context.pop();
4✔
261
                }
262
                super.endVisit(node);
3✔
263
        }
1✔
264

265
        @SuppressWarnings("unchecked")
266
        public boolean visitEnumConstantDeclaration(EnumConstantDeclaration node) {
267
                boolean hasInitBlock = (node.getAnonymousClassDeclaration() != null);
7✔
268

269
                for (Expression expr : (List<Expression>)node.arguments()) {
11✔
270
                        if (expr != null) {
2!
271
                                ctxtPushInitializerMethod(true,false); // EnumConstants are static.
7✔
272
                                hasInitBlock = true;
2✔
273
                                break;  // we recovered the INIT_BLOCK, no need to look for other declaration
1✔
274
                        }
275
                }
×
276
                if (hasInitBlock) {
2✔
277
                        ctxtPushInitializerMethod(true, false);
7✔
278
                }
279
                return hasInitBlock;
2✔
280
        }
281

282
        @SuppressWarnings("unchecked")
283
        public void endVisitEnumConstantDeclaration(EnumConstantDeclaration node) {
284
                if (node.getAnonymousClassDeclaration() != null) {
3✔
285
                        context.pop();  // pops the EntityDictionary.INIT_BLOCK_NAME method
4✔
286
                        return;
1✔
287
                }
288

289
                for (Expression expr : (List<Expression>)node.arguments()) {
11✔
290
                        if (expr != null) {
2!
291
                                context.pop();  // pops the EntityDictionary.INIT_BLOCK_NAME method
4✔
292
                                break;
1✔
293
                        }
294
                }
×
295
        }
1✔
296

297
    @SuppressWarnings("unchecked")
298
    public boolean hasInitBlock(FieldDeclaration node) {
299
        boolean hasInitBlock = false;
2✔
300
        for (var variableDeclaration : (List<VariableDeclaration>)node.fragments() ) {
11✔
301
            if (variableDeclaration.getInitializer() != null) {
3✔
302
                                ctxtPushInitializerMethod(Modifier.isStatic(node.getModifiers()), false);
9✔
303
                hasInitBlock = true;
2✔
304
                break;  // We recovered the correct initializer, no need to look for other fragments
1✔
305
            }
306
        }
1✔
307
        return hasInitBlock;
2✔
308
    }
309

310
        @SuppressWarnings("unchecked")
311
        public void endVisitFieldDeclaration(FieldDeclaration node) {
312
                for (var variableDeclaration : (List<VariableDeclaration>)node.fragments() ) {
11✔
313
                        if (variableDeclaration.getInitializer() != null) {
3✔
314
                                context.pop();  // Pops the initializer
4✔
315
                                break;
1✔
316
                        }
317
                }
1✔
318
        }
1✔
319

320
        /**
321
         * Recovers the correct initializer method, static or not.
322
         * Used in the case of instance/class initializer and initializing expressions of FieldDeclarations and EnumConstantDeclarations
323
         */
324
        protected org.moosetechnology.model.famix.famixjavaentities.Initializer ctxtPushInitializerMethod(Boolean isStatic, Boolean isInitializationBlock) {
325
                org.moosetechnology.model.famix.famixjavaentities.Initializer fmx = dico.ensureFamixInitializer((TWithMethods)context.topType(), isStatic, isInitializationBlock);
10✔
326
                if (fmx != null) {
2!
327
                        context.pushMethod(fmx);
4✔
328
                }
329
                return fmx;
2✔
330
        }
331

332
        public AnnotationTypeAttribute visitAnnotationTypeMemberDeclaration(AnnotationTypeMemberDeclaration node) {
333
                IMethodBinding bnd = node.resolveBinding();
3✔
334

335
                AnnotationTypeAttribute fmx = dico.getFamixAnnotationTypeAttribute(bnd, node.getName().getIdentifier(), (AnnotationType) context.topType());
12✔
336

337
                context.pushAnnotationMember(fmx);  // whether fmx==null or not
4✔
338
                return fmx;
2✔
339
        }
340

341
        protected String getAnonymousSuperTypeName() {
342
                return anonymousSuperTypeName.empty() ? null : anonymousSuperTypeName.peek();
11✔
343
        }
344

345
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc