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 // definition of this struct if available anywhere in the compilation unit 60 public Optional<Tree> definition() { 61 return definition; 62 } 63 64 public List<Tree> declarations() { 65 return declarations; 66 } 67 68 public List<FieldTree> fields() { 69 // Note that we have to include fields from nested annoymous unions and structs 70 // in the containing struct. 71 List<FieldTree> fields = new ArrayList<>(); 72 for (Tree decl : declarations) { 73 if (decl instanceof FieldTree) { 74 fields.add((FieldTree)decl); 75 } else if (decl instanceof StructTree) { 76 StructTree s = (StructTree)decl; 77 if (s.isAnonymous()) { 78 fields.addAll(s.fields()); 79 } 80 } 81 } 82 return Collections.unmodifiableList(fields); 83 } 84 85 public List<Tree> nestedTypes() { 86 // C structs and unions can have nested structs, unions and enums. 87 // And (even deeply) nested types are hoisted to the containing scope. 88 // i.e., nested structs/unions/enums are not scoped. 89 List<Tree> nested = new ArrayList<>(); 90 for (Tree decl : declarations) { 91 if (decl instanceof EnumTree) { 92 nested.add(decl); 93 } else if (decl instanceof StructTree) { 94 StructTree s = (StructTree)decl; 95 nested.add(s); 96 } 97 } 98 return Collections.unmodifiableList(nested); 99 } 100 101 @Override 102 public <R,D> R accept(TreeVisitor<R,D> visitor, D data) { 103 return visitor.visitStruct(this, data); 104 } 105 106 public boolean isUnion() { 107 return cursor().kind() == CursorKind.UnionDecl; 108 } 109 110 111 /** 112 * Is this struct/union declared as anonymous member of another struct/union? 113 * 114 * Example: 115 * 116 * struct X { 117 * struct { int i; int j; }; // <-- anonymous struct 118 * long l; 119 * }; 120 * 121 * Note: this is specific use of the word 'anonymous'. A struct with name() 122 * being empty is not necessarily anonymous in this usage. 123 * 124 * The structs in the following declarations are *not* anonymous eventhough 125 * the names of these structs are empty. 126 * 127 * struct { int i; int j; } thePoint; 128 * void func(struct { char* name; int len; } p1); 129 * typedef struct { int i; int j; } Point; 130 */ 131 public boolean isAnonymous() { 132 return cursor().isAnonymousStruct(); 133 } 134 135 public Layout layout(BiFunction<FieldTree, Layout, Layout> fieldMapper) { 136 TreeMaker m = new TreeMaker(); 137 return LayoutUtils.getRecordLayout(cursor().type(), (cursor, layout) -> { 138 return fieldMapper.apply(m.createField(cursor), layout); 139 }); 140 } 141 }