Skip to content
Snippets Groups Projects
Commit 7fa94991 authored by René Schöne's avatar René Schöne
Browse files

Show null children (shown per default)

parent f8512ae0
No related branches found
No related tags found
2 merge requests!60.3.6,!5Resolve "Show "null" children in tree"
Pipeline #12735 passed
DumpAst ::= DumpNode* <PackageName> BuildConfig PrintConfig ;
rel DumpAst.RootNode -> DumpNode ;
BuildConfig ::= GlobalPatternCollection:PatternCollection StyleInformation ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping* <TypeIgnorePattern> <IncludeEmptyString:boolean> <Debug:boolean>;
BuildConfig ::= StyleInformation GlobalPatternCollection:PatternCollection
ExcludeTypePattern:TypePatternCollectionMapping* IncludeTypePattern:TypePatternCollectionMapping*
<TypeIgnorePattern> <IncludeEmptyString:boolean> <ExcludeNullNodes:boolean> <Debug:boolean>;
TypePatternCollectionMapping ::= <TypeRegex> PatternCollection ;
PatternCollection ::= <TokenPattern> <ChildPattern> <RelationPattern> <AttributePattern> <NonterminalAttributePattern> ;
StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod> <TextColorMethod:StyleMethod>;
......@@ -9,7 +11,9 @@ StyleInformation ::= <NameMethod:StyleMethod> <BackgroundColorMethod:StyleMethod
PrintConfig ::= <Scale:double> <Version> <OrderChildren:boolean> Header* ;
Header ::= <Value> ;
DumpNode ::= <Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean> DumpChildNode* DumpToken* DumpRelation* /InvisiblePath/ ;
DumpNode ::= DumpChildNode* DumpToken* DumpRelation*
<Name> <Label> <BackgroundColor> <TextColor> <Object:Object> <Invisible:boolean>
/InvisiblePath/ ;
InnerDumpNode ;
rel InnerDumpNode.DumpNode <-> DumpNode.ContainerOfInner ;
......
......@@ -26,11 +26,23 @@ aspect GenerationBackend {
}
protected DumpNode DumpAst.transform(TransformationTransferInformation tti, Object obj, Source source)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (obj == null) {
return transform(tti, obj, source, false);
}
protected DumpNode DumpAst.transform(
TransformationTransferInformation tti, Object obj, Source source, boolean allowNullObj)
throws java.lang.reflect.InvocationTargetException, IllegalAccessException, NoSuchMethodException {
if (obj == null && !allowNullObj) {
return null;
}
DumpNode node = tti.transformed.get(obj);
String objClassName = obj.getClass().getSimpleName();
DumpNode node;
String objClassName;
if (obj == null) {
node = null;
objClassName = "null";
} else {
node = tti.transformed.get(obj);
objClassName = obj.getClass().getSimpleName();
}
if (node != null) {
if (source == Source.RELATION) {
return node;
......@@ -47,9 +59,7 @@ aspect GenerationBackend {
if (!node.isAstNode()) {
return node;
}
node.setLabel(getBuildConfig().getStyleInformation().getNameMethod().get(obj));
node.setBackgroundColor(getBuildConfig().getStyleInformation().getBackgroundColorMethod().get(obj));
node.setTextColor(getBuildConfig().getStyleInformation().getTextColorMethod().get(obj));
applyStyle(node);
// do not process node further if coming from a relation
if (source == Source.RELATION) {
tti.relationTargetsUnprocessed.put(node, true);
......@@ -58,13 +68,17 @@ aspect GenerationBackend {
if (source == Source.INVISIBLE_PARENT || !isTypeEnabled(objClassName)) {
node.setInvisible(true);
}
if (obj == null) {
// for a null object, we do not need any further analysis
return node;
}
final ClassAnalysisResult car = analyzeClass(obj.getClass());
// -- singleChild --
for (SingleChildMethod singleChildMethod : car.singleChildMethods()) {
Object target = singleChildMethod.getMethod().invoke(obj);
String childName = singleChildMethod.getName();
DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)));
if (target != null && targetNode != null) {
DumpNode targetNode = transform(tti, target, nextSource(source, !isChildEnabled(objClassName, childName)), !getBuildConfig().getExcludeNullNodes());
if (targetNode != null) {
DumpNormalChildNode normalChild = new DumpNormalChildNode();
normalChild.setName(childName);
normalChild.setDumpNode(targetNode);
......@@ -143,6 +157,13 @@ aspect GenerationBackend {
return node;
}
private void DumpAst.applyStyle(DumpNode node) {
Object obj = node.getObject();
node.setLabel(getBuildConfig().getStyleInformation().getNameMethod().get(obj));
node.setBackgroundColor(getBuildConfig().getStyleInformation().getBackgroundColorMethod().get(obj));
node.setTextColor(getBuildConfig().getStyleInformation().getTextColorMethod().get(obj));
}
private Source DumpAst.nextSource(Source currentSource, boolean shouldBeInvisible) {
return currentSource == Source.INVISIBLE_PARENT ? Source.INVISIBLE_PARENT :
(shouldBeInvisible ? Source.INVISIBLE_PARENT : Source.PARENT);
......@@ -415,6 +436,10 @@ aspect GenerationBackend {
// --- isAstNode ---
syn boolean DumpNode.isAstNode() {
if (getObject() == null) {
// this is only possible for normal child nodes, and they are ast nodes
return true;
}
Class<?> clazz = getObject().getClass();
for (java.lang.reflect.Method method : clazz.getMethods()) {
if ("init$Children".equals(method.getName()) && method.getParameterCount() == 0) {
......@@ -462,7 +487,6 @@ aspect GenerationBackend {
}
}
// --- myChildren ---
syn java.util.List<DumpNode> DumpNode.myChildren() {
java.util.List<DumpNode> result = new java.util.ArrayList<>();
......@@ -579,7 +603,7 @@ aspect GenerationBackend {
static StyleInformation StyleInformation.createDefault() {
StyleInformation result = new StyleInformation();
result.setNameMethod(n -> n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode()));
result.setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName() + "@" + Integer.toHexString(n.hashCode()));
result.setBackgroundColorMethod(n -> "");
result.setTextColorMethod(n -> "");
return result;
......
......@@ -308,6 +308,16 @@ public class DumpBuilder {
}
}
public DumpBuilder excludeNullNodes() {
buildConfig.setExcludeNullNodes(true);
return this;
}
public DumpBuilder includeNullNodes() {
buildConfig.setExcludeNullNodes(false);
return this;
}
public DumpBuilder customPreamble(String option) {
printConfig.addHeader(new Header(option));
return this;
......
......@@ -35,7 +35,7 @@ public class TestDumperMain {
builder.includeAttributes("simpleAttr")
.orderChildren()
.includeNonterminalAttributes("getCalculated")
.setNameMethod(n -> n.getClass().getSimpleName());
.setNameMethod(n -> n == null ? "null" : n.getClass().getSimpleName());
System.out.println(">> PlantUml");
DumpAst dumpAst = builder.build();
......
......@@ -31,9 +31,9 @@ public class TestSimple {
@Test void testChildlessNonterminal() {
Root root = createRoot(createA(A_NAME, a -> a.setD(new D())), null);
List<DumpNode> nodes = TestUtils.dumpModel(root);
Optional<DumpNode> optionalCDumpNode = nodes.stream().filter(n -> n.getObject() instanceof D).findFirst();
assertTrue(optionalCDumpNode.isPresent());
assertTrue(optionalCDumpNode.get().isAstNode());
Optional<DumpNode> actualD = nodes.stream().filter(n -> n.getObject() instanceof D).findFirst();
assertTrue(actualD.isPresent());
assertTrue(actualD.get().isAstNode());
}
@Test
......@@ -49,6 +49,22 @@ public class TestSimple {
assertThatMapOf(normalChildren(actualRoot)).containsExactlyInAnyOrder(tuple("A", A_NAME));
}
@Test
public void testOneNormalChildIncludeNullNodes() {
Root root = createRoot(createA(A_NAME), null);
List<DumpNode> nodes = TestUtils.dumpModel(root, DumpBuilder::includeNullNodes);
assertThat(nodes).flatExtracting(NAME_EXTRACTOR).containsExactlyInAnyOrder(
ROOT_NAME, A_NAME, null, null, null, null);
DumpNode actualRoot = TestUtils.findByName(nodes, ROOT_NAME);
assertEquals(1, actualRoot.getNumDumpToken());
assertEquals(2, actualRoot.getNumDumpChildNode());
assertEquals(0, actualRoot.getNumDumpRelation());
DumpNode actualA = TestUtils.findByName(nodes, A_NAME);
assertEquals(3, actualA.getNumDumpChildNode());
}
@Test
public void testListChildren() {
Root root = createRoot(null, null, createB(B1_NAME), createB(B2_NAME), createB(B3_NAME));
......
......@@ -156,6 +156,7 @@ public class TestUtils {
public static List<DumpNode> dumpModel(Object target, Consumer<DumpBuilder> options) {
ExposingDumpBuilder builder = new ExposingDumpBuilder(target);
builder.excludeNullNodes();
options.accept(builder);
DumpAst dumpAst = builder.build();
// let mustache run, but ignore result
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment