Split out isBitsType()
[mdsal.git] / binding / mdsal-binding-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / java / api / generator / NestedJavaGeneratedType.java
1 /*
2  * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.binding.java.api.generator;
9
10 import static com.google.common.base.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.ImmutableList;
14 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
15 import java.util.ArrayDeque;
16 import java.util.Deque;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Optional;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
23 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
24
25 /**
26  * A type which is nested inside some other type. It defers import decisions to its enclosing type, eventually arriving
27  * at a {@link TopLevelJavaGeneratedType}.
28  *
29  * @author Robert Varga
30  */
31 @NonNullByDefault
32 final class NestedJavaGeneratedType extends AbstractJavaGeneratedType {
33     private final AbstractJavaGeneratedType enclosingType;
34
35     NestedJavaGeneratedType(final AbstractJavaGeneratedType enclosingType, final GeneratedType genType) {
36         super(genType);
37         this.enclosingType = requireNonNull(enclosingType);
38     }
39
40     @Override
41     boolean importCheckedType(final JavaTypeName type) {
42         // Defer to enclosing type, which needs to re-run its checks
43         return enclosingType.checkAndImportType(type);
44     }
45
46     @Override
47     String localTypeName(final JavaTypeName type) {
48         // Check if the type is a reference to our immediately-enclosing type
49         if (enclosingType.getName().equals(type)) {
50             return enclosingType.getSimpleName();
51         }
52
53         final @Nullable List<String> descendant = findDescandantPath(type);
54         if (descendant == null) {
55             // The type is not present in our hierarchy, defer to our immediately-enclosing type, which may be able
56             // to find the target.
57             return enclosingType.localTypeName(type);
58         }
59
60         // Target type is a declared as a enclosed type of us and we have the path where it lurks.
61         final Iterator<String> it = descendant.iterator();
62         final StringBuilder sb = new StringBuilder().append(it.next());
63         while (it.hasNext()) {
64             sb.append('.').append(it.next());
65         }
66         return sb.toString();
67     }
68
69     @SuppressFBWarnings(value = "NP_NONNULL_RETURN_VIOLATION",
70             justification = "SpotBugs confusion @Nullable vs @NonNullByDefault")
71     private @Nullable List<String> findDescandantPath(final JavaTypeName type) {
72         Optional<JavaTypeName> optEnclosing = type.immediatelyEnclosingClass();
73         verify(optEnclosing.isPresent());
74
75         final Deque<String> queue = new ArrayDeque<>();
76         queue.addFirst(type.simpleName());
77         while (optEnclosing.isPresent()) {
78             final JavaTypeName enclosing = optEnclosing.get();
79             if (enclosing.equals(getName())) {
80                 return ImmutableList.copyOf(queue);
81             }
82
83             queue.addFirst(enclosing.simpleName());
84             optEnclosing = enclosing.immediatelyEnclosingClass();
85         }
86
87         return null;
88     }
89 }