1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package com.sun.tools.jextract.tree; 24 25 import java.foreign.layout.Layout; 26 import java.util.ArrayList; 27 import java.util.Collections; 28 import java.util.List; 29 import java.util.Objects; 30 import java.util.Optional; 31 import java.util.function.BiFunction; 32 import jdk.internal.clang.Cursor; 33 import jdk.internal.clang.CursorKind; 34 35 public class StructTree extends Tree { 36 private final Optional<Tree> definition; 37 private final List<Tree> declarations; 38 39 StructTree(Cursor c, Optional<Tree> definition, List<Tree> decls) { 40 this(c, definition, decls, c.spelling()); 41 } 42 43 private StructTree(Cursor c, Optional<Tree> definition, List<Tree> decls, String name) { 44 super(c, name); 45 this.definition = c.isDefinition()? Optional.of(this) : Objects.requireNonNull(definition); 46 this.declarations = Collections.unmodifiableList(decls); 47 } 48 49 @Override 50 public StructTree withName(String newName) { 51 return name().equals(newName)? this : 52 new StructTree(cursor(), definition, declarations, newName); 53 } 54 55 public StructTree withNameAndDecls(String newName, List<Tree> newDecls) { 56 return new StructTree(cursor(), definition, newDecls, newName); 57 } 58 59 public Optional<Tree> definition() { 60 return definition; 61 } 62 63 public List<Tree> declarations() { 64 return declarations; 65 } 66 67 public List<FieldTree> fields() { 68 // Note that we have to include fields from nested annoymous unions and structs 69 // in the containing struct. 70 List<FieldTree> fields = new ArrayList<>(); 71 for (Tree decl : declarations) { 72 if (decl instanceof FieldTree) { 73 fields.add((FieldTree)decl); 74 } else if (decl instanceof StructTree) { 75 StructTree s = (StructTree)decl; 76 if (s.isAnonymous()) { 77 fields.addAll(s.fields()); 78 } 79 } 80 } 81 return Collections.unmodifiableList(fields); 82 } 83 84 public List<Tree> nestedTypes() { 85 // C structs and unions can have nested structs, unions and enums. 86 // And (even deeply) nested types are hoisted to the containing scope. 87 // i.e., nested structs/unions/enums are not scoped. 88 List<Tree> nested = new ArrayList<>(); 89 for (Tree decl : declarations) { 90 if (decl instanceof EnumTree) { 91 nested.add(decl); 92 } else if (decl instanceof StructTree) { 93 StructTree s = (StructTree)decl; 94 if (!s.isAnonymous()) { 95 nested.add(s); 96 } 97 nested.addAll(s.nestedTypes()); 98 } 99 } 100 return Collections.unmodifiableList(nested); 101 } 102 103 @Override 104 public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { 105 return visitor.visitStruct(this, data); 106 } 107 108 public boolean isUnion() { 109 return cursor().kind() == CursorKind.UnionDecl; 110 } 111 112 113 /** 114 * Is this struct/union declared as anonymous member of another struct/union? 115 * 116 * Example: 117 * 118 * struct X { 119 * struct { int i; int j; }; // <-- anonymous struct 120 * long l; 121 * }; 122 * 123 * Note: this is specific use of the word 'anonymous'. A struct with name() 124 * being empty is not necessarily anonymous in this usage. 125 * 126 * The structs in the following declarations are *not* anonymous eventhough 127 * the names of these structs are empty. 128 * 129 * struct { int i; int j; } thePoint; 130 * void func(struct { char* name; int len; } p1); 131 * typedef struct { int i; int j; } Point; 132 */ 133 public boolean isAnonymous() { 134 return cursor().isAnonymousStruct(); 135 } 136 137 public Layout layout(BiFunction<FieldTree, Layout, Layout> fieldMapper) { 138 TreeMaker m = new TreeMaker(); 139 return LayoutUtils.getRecordLayout(cursor().type(), (cursor, layout) -> { 140 return fieldMapper.apply(m.createField(cursor), layout); 141 }); 142 } 143 }