changeset 58408:cd31afbf3e78 foreign+vector

Automatic merge with foreign
author mcimadamore
date Tue, 18 Sep 2018 19:14:07 +0200
parents 7e9980e0ed34 d2d130f4b312
children e98cc9487657
files
diffstat 21 files changed, 639 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java	Tue Sep 18 19:14:07 2018 +0200
@@ -166,10 +166,7 @@
      */
     private void addField(ClassVisitor cw, Tree tree, Type parentType) {
         String fieldName = tree.name();
-        if (fieldName.isEmpty()) {
-            //skip anon fields
-            return;
-        }
+        assert !fieldName.isEmpty();
         Type type = tree.type();
         JType jt = owner.globalLookup(type);
         assert (jt != null);
@@ -234,7 +231,7 @@
 
     @Override
     public Void visitStruct(StructTree structTree, JType jt) {
-        String nativeName = structTree.identifier();
+        String nativeName = structTree.name();
         Type type = structTree.type();
         logger.fine(() -> "Create struct: " + nativeName);
 
@@ -305,7 +302,7 @@
     }
 
     private void createAnnotationCls(Tree tree) {
-        String nativeName = tree.identifier();
+        String nativeName = tree.name();
         logger.fine(() -> "Create annotation for: " + nativeName);
 
         String intf = Utils.toClassName(nativeName);
@@ -345,7 +342,7 @@
             intf = ((JType.InnerType) fnif.type).getName();
             nativeName = "anonymous function";
         } else {
-            nativeName = tree.identifier();
+            nativeName = tree.name();
             intf = Utils.toClassName(nativeName);
         }
         logger.fine(() -> "Create FunctionalInterface " + intf);
@@ -388,13 +385,6 @@
 
     @Override
     public Void visitTypedef(TypedefTree typedefTree, JType jt) {
-        Type t = typedefTree.type();
-        if (t.canonicalType().kind() == TypeKind.Enum &&
-            t.spelling().equals(t.canonicalType().getDeclarationCursor().spelling())) {
-            logger.fine("Skip redundant typedef " + t.spelling());
-            return null;
-        }
-
         // anonymous typedef struct {} xxx will not get TypeAlias
         if (jt instanceof TypeAlias) {
             TypeAlias alias = (TypeAlias) jt;
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/Context.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/Context.java	Tue Sep 18 19:14:07 2018 +0200
@@ -52,8 +52,9 @@
 import java.util.stream.Collectors;
 import java.util.zip.ZipEntry;
 import com.sun.tools.jextract.parser.Parser;
+import com.sun.tools.jextract.tree.FunctionTree;
+import com.sun.tools.jextract.tree.HeaderTree;
 import com.sun.tools.jextract.tree.Tree;
-import com.sun.tools.jextract.tree.HeaderTree;
 
 import static java.nio.file.StandardOpenOption.CREATE;
 import static java.nio.file.StandardOpenOption.TRUNCATE_EXISTING;
@@ -341,35 +342,34 @@
         parse(header -> new AsmCodeFactory(this, header));
     }
 
-    private boolean filterCursor(Cursor c) {
-        if (c.isDeclaration()) {
-            Type type = c.type();
-            if (type.kind() == TypeKind.FunctionProto ||
-                type.kind() == TypeKind.FunctionNoProto) {
-                String name = c.spelling();
+    private boolean symbolFilter(Tree tree) {
+         String name = tree.name();
+         if (isSymbolExcluded(name)) {
+             return false;
+         }
 
-                if (isSymbolExcluded(name)) {
-                    return false;
-                }
+         // check for function symbols in libraries & warn missing symbols
+         if (tree instanceof FunctionTree && !isSymbolFound(name)) {
+             err.println(Main.format("warn.symbol.not.found", name));
+         }
 
-                if (!isSymbolFound(name)) {
-                    err.println(Main.format("warn.symbol.not.found", name));
-                }
-            }
-        }
-        return true;
+         return true;
     }
 
     public void parse(Function<HeaderFile, AsmCodeFactory> fn) {
         initSymChecker();
         initSymFilter();
 
-        List<HeaderTree> headers = parser.parse(sources, clangArgs, this::filterCursor);
+        List<HeaderTree> headers = parser.parse(sources, clangArgs);
         processHeaders(headers, fn);
     }
 
     private void processHeaders(List<HeaderTree> headers, Function<HeaderFile, AsmCodeFactory> fn) {
-        headers.forEach(header -> {
+        headers.stream().
+                map((new TreeFilter(this::symbolFilter))::transform).
+                map((new TypedefHandler())::transform).
+                map((new EmptyNameHandler())::transform).
+                forEach(header -> {
             HeaderFile hf = headerMap.computeIfAbsent(header.path(), p -> getHeaderFile(p, null));
             hf.useLibraries(libraryNames, libraryPaths);
             hf.useCodeFactory(fn.apply(hf));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/EmptyNameHandler.java	Tue Sep 18 19:14:07 2018 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.jextract;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import com.sun.tools.jextract.parser.Parser;
+import com.sun.tools.jextract.tree.EnumTree;
+import com.sun.tools.jextract.tree.FieldTree;
+import com.sun.tools.jextract.tree.LayoutUtils;
+import com.sun.tools.jextract.tree.HeaderTree;
+import com.sun.tools.jextract.tree.SimpleTreeVisitor;
+import com.sun.tools.jextract.tree.StructTree;
+import com.sun.tools.jextract.tree.Tree;
+import com.sun.tools.jextract.tree.TreeMaker;
+import com.sun.tools.jextract.tree.TreePrinter;
+import jdk.internal.clang.Cursor;
+
+/**
+ * This tree visitor handles the tree empty names encountered in the tree
+ * so that subsequent passes need not check tree.name() for empty string.
+ *
+ * 1. Names are generated & set for anonymous structs & unions.
+ * 2. Anonymous (bit) FieldTree instances are removed.
+ */
+final class EmptyNameHandler extends SimpleTreeVisitor<Tree, Void> {
+    private final TreeMaker treeMaker = new TreeMaker();
+
+    HeaderTree transform(HeaderTree ht) {
+        return (HeaderTree)ht.accept(this, null);
+    }
+
+    // generate unique name for an empty name
+    private String generateName(Tree tree) {
+        return LayoutUtils.getName(tree);
+    }
+
+    @Override
+    public Tree defaultAction(Tree tree, Void v) {
+        return tree;
+    }
+
+    @Override
+    public Tree visitHeader(HeaderTree ht, Void v) {
+        List<Tree> decls =  ht.declarations().stream().
+            map(decl -> decl.accept(this, null)).
+            collect(Collectors.toList());
+        return treeMaker.createHeader(ht.cursor(), ht.path(), decls);
+    }
+
+    @Override
+    public Tree visitStruct(StructTree s, Void v) {
+        // Common simple case. No nested names and no anonymous field names.
+        // We just need to check struct name itself is empty or not.
+        if (s.nestedTypes().isEmpty() && !hasAnonymousFields(s)) {
+            /*
+             * Examples:
+             *
+             *   struct { int i } x; // global variable of anon. struct type
+             *   void func(struct { int x; } p); // param of anon. struct type
+             */
+            if (s.name().isEmpty()) {
+                return s.withName(generateName(s));
+            } else {
+                // all fine with this struct
+                return s;
+            }
+        } else {
+            // handle all nested types
+            return renameRecursively(s);
+        }
+    }
+
+    // does the given struct has any anonymous (bit) field?
+    private boolean hasAnonymousFields(StructTree s) {
+        return s.fields().stream().map(f -> f.name().isEmpty()).findFirst().isPresent();
+    }
+
+    private StructTree renameRecursively(StructTree s) {
+        List<Tree> newDecls = s.declarations().stream().map(decl -> {
+            if (decl instanceof StructTree) {
+                return renameRecursively((StructTree)decl);
+            } else if (decl instanceof FieldTree && decl.name().isEmpty()) {
+                /*
+                 * Skip anonymous fields. This happens in the following case:
+                 *
+                 * struct {
+                 *    int  :23; // anonymous bit field
+                 *    int x:9;
+                 * }
+                 */
+
+                return null;
+            } else {
+                return decl;
+            }
+        }).filter(d -> d != null).collect(Collectors.toList());
+
+        return s.withNameAndDecls(generateName(s), newDecls);
+    }
+
+    // test main to manually check this visitor
+    public static void main(String[] args) {
+        if (args.length == 0) {
+            System.err.println("Expected a header file");
+            return;
+        }
+
+        Parser p = new Parser(true);
+        List<Path> paths = Arrays.stream(args).map(Paths::get).collect(Collectors.toList());
+        Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract");
+        List<String> clangArgs = List.of("-I" + builtinInc);
+        List<HeaderTree> headers = p.parse(paths, clangArgs);
+        TreePrinter printer = new TreePrinter();
+        EmptyNameHandler handler = new EmptyNameHandler();
+        for (HeaderTree ht : headers) {
+            handler.transform(ht).accept(printer, null);
+        }
+    }
+}
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/HeaderFile.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/HeaderFile.java	Tue Sep 18 19:14:07 2018 +0200
@@ -149,7 +149,7 @@
 
     private JType doRecord(Type t) {
         assert(t.kind() == TypeKind.Record);
-        String name = Utils.toClassName(Utils.getIdentifier(t));
+        String name = Utils.toClassName(Utils.getName(t));
         Cursor dcl = t.getDeclarationCursor();
         // Define record locally but not declared in this file, likely a built-in type.
         // __builtin_va_list is such a type.
@@ -197,7 +197,7 @@
                 break;
             case Enum:
                 String name = Utils.toInternalName(pkgName, clsName,
-                        Utils.toClassName(Utils.getIdentifier(t)));
+                        Utils.toClassName(Utils.getName(t)));
                 jt = TypeAlias.of(name, JType.Int);
                 break;
             case Invalid:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/TreeFilter.java	Tue Sep 18 19:14:07 2018 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.jextract;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+import com.sun.tools.jextract.parser.Parser;
+import com.sun.tools.jextract.tree.FunctionTree;
+import com.sun.tools.jextract.tree.HeaderTree;
+import com.sun.tools.jextract.tree.MacroTree;
+import com.sun.tools.jextract.tree.SimpleTreeVisitor;
+import com.sun.tools.jextract.tree.Tree;
+import com.sun.tools.jextract.tree.VarTree;
+import com.sun.tools.jextract.tree.TreeMaker;
+import com.sun.tools.jextract.tree.TreePrinter;
+
+/**
+ * This visitor filters variable, function, macro trees
+ * based on a Tree Predicate initialized.
+ */
+final class TreeFilter extends SimpleTreeVisitor<Tree, Void> {
+    private final TreeMaker treeMaker = new TreeMaker();
+    private final Predicate<Tree> filter;
+
+    TreeFilter(Predicate<Tree> filter) {
+        this.filter = filter;
+    }
+
+    private Tree filterTree(Tree tree) {
+        return filter.test(tree)? tree : null;
+    }
+
+    HeaderTree transform(HeaderTree ht) {
+        return (HeaderTree)ht.accept(this, null);
+    }
+
+    @Override
+    public Tree defaultAction(Tree tree, Void v) {
+        return tree;
+    }
+
+    @Override
+    public Tree visitFunction(FunctionTree ft, Void v) {
+        return filterTree(ft);
+    }
+
+    @Override
+    public Tree visitMacro(MacroTree mt, Void v) {
+        return filterTree(mt);
+    }
+
+    @Override
+    public Tree visitHeader(HeaderTree ht, Void v) {
+        List<Tree> decls =  ht.declarations().stream().
+            map(decl -> decl.accept(this, null)).
+            filter(decl -> decl != null).
+            collect(Collectors.toList());
+        return treeMaker.createHeader(ht.cursor(), ht.path(), decls);
+    }
+
+    @Override
+    public Tree visitVar(VarTree vt, Void v) {
+        return filterTree(vt);
+    }
+
+    // test main to manually check this visitor
+    // Usage: <header-file> [<regex-for-symbols-to-include>]
+    public static void main(String[] args) {
+        if (args.length == 0) {
+            System.err.println("Expected a header file");
+            return;
+        }
+
+        Parser p = new Parser(true);
+        List<Path> paths = List.of(Paths.get(args[0]));
+        Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract");
+        List<String> clangArgs = List.of("-I" + builtinInc);
+        List<HeaderTree> headers = p.parse(paths, clangArgs);
+        TreePrinter printer = new TreePrinter();
+        Predicate<Tree> nameFilter =  args.length > 1? t->t.name().matches(args[1]) : t->true;
+        TreeFilter filter = new TreeFilter(nameFilter);
+        for (HeaderTree ht : headers) {
+            filter.transform(ht).accept(printer, null);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/TypedefHandler.java	Tue Sep 18 19:14:07 2018 +0200
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.tools.jextract;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import com.sun.tools.jextract.parser.Parser;
+import com.sun.tools.jextract.tree.EnumTree;
+import com.sun.tools.jextract.tree.HeaderTree;
+import com.sun.tools.jextract.tree.SimpleTreeVisitor;
+import com.sun.tools.jextract.tree.StructTree;
+import com.sun.tools.jextract.tree.Tree;
+import com.sun.tools.jextract.tree.TreeMaker;
+import com.sun.tools.jextract.tree.TreePrinter;
+import com.sun.tools.jextract.tree.TypedefTree;
+import jdk.internal.clang.Cursor;
+
+/**
+ * This visitor handles certain typedef declarations.
+ *
+ * 1. Remove redundant typedefs.
+ * 2. Rename typedef'ed anonymous type definitions like
+ *        typedef struct { int x; int y; } Point;
+ */
+final class TypedefHandler extends SimpleTreeVisitor<Void, Void> {
+    private final TreeMaker treeMaker = new TreeMaker();
+
+    // Potential Tree instances that will go into transformed HeaderTree
+    // are collected in this list.
+    private final List<Tree> decls = new ArrayList<>();
+
+    // Tree instances that are to be replaced from "decls" list are
+    // saved in the following Map.
+    private final Map<Cursor, Tree> replacements = new HashMap<>();
+
+    HeaderTree transform(HeaderTree ht) {
+        // Process all header declarations are collect potential
+        // declarations that will go into transformed HeaderTree
+        // into the this.decls field.
+        ht.accept(this, null);
+
+        // Replace trees from this.decls with Trees found in this.replacements.
+        // We need this two step process so that named StructTree instances
+        // will replace with original unnamed StructTree instances.
+        List<Tree> newDecls = decls.stream().map(tx -> {
+            if (replacements.containsKey(tx.cursor())) {
+                return replacements.get(tx.cursor());
+            } else {
+                return tx;
+            }
+        }).collect(Collectors.toList());
+
+        return treeMaker.createHeader(ht.cursor(), ht.path(), newDecls);
+    }
+
+    @Override
+    public Void defaultAction(Tree tree, Void v) {
+        decls.add(tree);
+        return null;
+    }
+
+    @Override
+    public Void visitHeader(HeaderTree ht, Void v) {
+        ht.declarations().forEach(decl -> decl.accept(this, null));
+        return null;
+    }
+
+    @Override
+    public Void visitTypedef(TypedefTree tt, Void v) {
+        Optional<Tree> def = tt.typeDefinition();
+        if (def.isPresent()) {
+            Tree defTree = def.get();
+            if (defTree instanceof StructTree) {
+                if (defTree.name().isEmpty()) {
+                    /**
+                     * typedef struct { int x; int y; } Point
+                     *
+                     * is mapped to two Cursors by clang. First one for anonymous struct decl.
+                     * and second one for typedef decl. We map it as a single named struct
+                     * declaration.
+                     */
+                    replacements.put(defTree.cursor(), ((StructTree)defTree).withName(tt.name()));
+                    return null;
+                } else if (defTree.name().equals(tt.name())) {
+                    /*
+                     * Remove redundant typedef like:
+                     *
+                     * typedef struct Point { int x; int y; } Point
+                     */
+                    return null;
+                }
+            } else if (defTree instanceof EnumTree && defTree.name().equals(tt.name())) {
+                /*
+                 * Remove redundant typedef like:
+                 *
+                 * typedef enum Color { R, G, B} Color
+                 */
+                return null;
+            }
+        }
+
+        decls.add(tt);
+        return null;
+    }
+
+    // test main to manually check this visitor
+    public static void main(String[] args) {
+        if (args.length == 0) {
+            System.err.println("Expected a header file");
+            return;
+        }
+
+        Parser p = new Parser(true);
+        List<Path> paths = Arrays.stream(args).map(Paths::get).collect(Collectors.toList());
+        Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract");
+        List<String> clangArgs = List.of("-I" + builtinInc);
+        List<HeaderTree> headers = p.parse(paths, clangArgs);
+        TreePrinter printer = new TreePrinter();
+        TypedefHandler handler = new TypedefHandler();
+        for (HeaderTree ht : headers) {
+            handler.transform(ht).accept(printer, null);
+        }
+    }
+}
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/Utils.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/Utils.java	Tue Sep 18 19:14:07 2018 +0200
@@ -117,8 +117,8 @@
         return sb.toString();
     }
 
-    public static String getIdentifier(Type type) {
-        return LayoutUtils.getIdentifier(type);
+    public static String getName(Type type) {
+        return LayoutUtils.getName(type);
     }
 
     public static String ClassToDescriptor(Class<?> cls) {
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/parser/FindSymbol.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/parser/FindSymbol.java	Tue Sep 18 19:14:07 2018 +0200
@@ -46,7 +46,7 @@
         final List<String> clangArgs = List.of("-I" + builtinInc);
 
         final Parser parser = new Parser(true);
-        final List<HeaderTree> headers = parser.parse(paths, clangArgs, c->true);
+        final List<HeaderTree> headers = parser.parse(paths, clangArgs);
         final Printer p = new Printer();
         final HeaderTree tu = headers.get(0);
 
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/parser/Parser.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/parser/Parser.java	Tue Sep 18 19:14:07 2018 +0200
@@ -33,7 +33,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.function.Predicate;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import jdk.internal.clang.Cursor;
@@ -70,7 +69,7 @@
             new PrintWriter(System.err, true), supportMacros);
     }
 
-    public List<HeaderTree> parse(Collection<Path> paths, Collection<String> args, Predicate<Cursor> include) {
+    public List<HeaderTree> parse(Collection<Path> paths, Collection<String> args) {
         final List<HeaderTree> headers = new ArrayList<>();
         final Index index = LibClang.createIndex();
         for (Path path : paths) {
@@ -100,7 +99,6 @@
             MacroParser macroParser = new MacroParser();
             List<Tree> decls = new ArrayList<>();
             tuCursor.children().
-                filter(c -> include.test(c)).
                 peek(c -> logger.finest(
                     () -> "Cursor: " + c.spelling() + "@" + c.USR() + "?" + c.isDeclaration())).
                 forEach(c -> {
@@ -186,7 +184,7 @@
         List<Path> paths = Arrays.stream(args).map(Paths::get).collect(Collectors.toList());
         Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract");
         List<String> clangArgs = List.of("-I" + builtinInc);
-        List<HeaderTree> headers = p.parse(paths, clangArgs, c->true);
+        List<HeaderTree> headers = p.parse(paths, clangArgs);
         TreePrinter printer = new TreePrinter();
         for (HeaderTree ht : headers) {
             ht.accept(printer, null);
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/EnumTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/EnumTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -24,14 +24,32 @@
 
 import java.util.List;
 import java.util.Collections;
+import java.util.Objects;
+import java.util.Optional;
 import jdk.internal.clang.Cursor;
 
 public class EnumTree extends Tree {
+    private final Optional<Tree> definition;
     private final List<FieldTree> constants;
 
-    public EnumTree(Cursor c, List<FieldTree> constants) {
-        super(c);
-        this.constants = Collections.unmodifiableList(constants);
+    EnumTree(Cursor c, Optional<Tree> definition, List<FieldTree> consts) {
+        this(c, definition, consts, c.spelling());
+    }
+
+    private EnumTree(Cursor c, Optional<Tree> definition, List<FieldTree> consts, String name) {
+        super(c, name);
+        this.definition = c.isDefinition()? Optional.of(this) : Objects.requireNonNull(definition);
+        this.constants = Collections.unmodifiableList(consts);
+    }
+
+    @Override
+    public EnumTree withName(String newName) {
+        return name().equals(newName)? this :
+            new EnumTree(cursor(), definition, constants, newName);
+    }
+
+    public Optional<Tree> definition() {
+        return definition;
     }
 
     public List<FieldTree> constants() {
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/FieldTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/FieldTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -27,8 +27,17 @@
 import jdk.internal.clang.CursorKind;
 
 public class FieldTree extends Tree {
-    public FieldTree(Cursor c) {
-        super(c);
+    FieldTree(Cursor c) {
+        this(c, c.spelling());
+    }
+
+    private FieldTree(Cursor c, String name) {
+        super(c, name);
+    }
+
+    @Override
+    public FieldTree withName(String newName) {
+        return name().equals(newName)? this : new FieldTree(cursor(), newName);
     }
 
     @Override
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/FunctionTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/FunctionTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -30,8 +30,17 @@
 import jdk.internal.clang.Type;
 
 public class FunctionTree extends Tree {
-    public FunctionTree(Cursor c) {
-        super(c);
+    FunctionTree(Cursor c) {
+        this(c, c.spelling());
+    }
+
+    private FunctionTree(Cursor c, String name) {
+        super(c, name);
+    }
+
+    @Override
+    public FunctionTree withName(String newName) {
+        return name().equals(newName)? this : new FunctionTree(cursor(), newName);
     }
 
     @Override
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/HeaderTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/HeaderTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -31,12 +31,21 @@
     private final Path path;
     private final List<Tree> declarations;
 
-    public HeaderTree(Cursor c, Path path, List<Tree> declarations) {
-        super(c);
+    HeaderTree(Cursor c, Path path, List<Tree> declarations) {
+        this(c, path, declarations, c.spelling());
+    }
+
+    private HeaderTree(Cursor c, Path path, List<Tree> declarations, String name) {
+        super(c, name);
         this.path = path;
         this.declarations = Collections.unmodifiableList(declarations);
     }
 
+    @Override
+    public HeaderTree withName(String newName) {
+        return name().equals(newName)? this : new HeaderTree(cursor(), path, declarations, newName);
+    }
+
     public Path path() {
         return path;
     }
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/LayoutUtils.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/LayoutUtils.java	Tue Sep 18 19:14:07 2018 +0200
@@ -49,23 +49,27 @@
 public final class LayoutUtils {
     private LayoutUtils() {}
 
-    public static String getIdentifier(Type type) {
+    public static String getName(Type type) {
         Cursor c = type.getDeclarationCursor();
         if (c.isInvalid()) {
             return type.spelling();
         }
-        return getIdentifier(c);
+        return getName(c);
     }
 
-    static String getIdentifier(Cursor cursor) {
+    public static String getName(Tree tree) {
+        String name = tree.name();
+        return name.isEmpty()? getName(tree.cursor()) : name;
+    }
+
+    private static String getName(Cursor cursor) {
         // Use cursor name instead of type name, this way we don't have struct
         // or enum prefix
         String nativeName = cursor.spelling();
         if (nativeName.isEmpty()) {
-            // This happens when a typedef an anonymous struct, i.e., typedef struct {} type;
             Type t = cursor.type();
             nativeName = t.spelling();
-            if (nativeName.contains("::")) {
+            if (nativeName.contains("::") || nativeName.contains(" ")) {
                 SourceLocation.Location loc = cursor.getSourceLocation().getFileLocation();
                 return "anon$"
                         + loc.path().getFileName().toString().replaceAll("\\.", "_")
@@ -196,7 +200,7 @@
     private static Layout getRecordReferenceLayout(Type t) {
         //symbolic reference
         return Unresolved.of()
-                .withAnnotation(Layout.NAME, getIdentifier(t.canonicalType()));
+                .withAnnotation(Layout.NAME, getName(t.canonicalType()));
     }
 
     static Layout getRecordLayout(Type t, BiFunction<Cursor, Layout, Layout> fieldMapper) {
@@ -257,7 +261,7 @@
         Layout[] fields = fieldLayouts.toArray(new Layout[0]);
         Group g = isUnion ?
                 Group.union(fields) : Group.struct(fields);
-        return g.withAnnotation(Layout.NAME, getIdentifier(cu));
+        return g.withAnnotation(Layout.NAME, getName(cu));
     }
 
     private static Layout fieldLayout(boolean isUnion, Cursor c, BiFunction<Cursor, Layout, Layout> fieldMapper) {
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/MacroTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/MacroTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -28,11 +28,20 @@
 public class MacroTree extends Tree {
     private final Optional<Object> value;
 
-    public MacroTree(Cursor c, Optional<Object> value) {
-        super(c);
+    MacroTree(Cursor c, Optional<Object> value) {
+        this(c, value, c.spelling());
+    }
+
+    private MacroTree(Cursor c, Optional<Object> value, String name) {
+        super(c, name);
         this.value = value;
     }
 
+    @Override
+    public MacroTree withName(String newName) {
+        return name().equals(newName)? this : new MacroTree(cursor(), value, newName);
+    }
+
     public Optional<Object> value() {
         return value;
     }
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/StructTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/StructTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -26,16 +26,38 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
 import java.util.function.BiFunction;
 import jdk.internal.clang.Cursor;
 import jdk.internal.clang.CursorKind;
 
 public class StructTree extends Tree {
+    private final Optional<Tree> definition;
     private final List<Tree> declarations;
 
-    public StructTree(Cursor c, List<Tree> declarations) {
-        super(c);
-        this.declarations = Collections.unmodifiableList(declarations);
+    StructTree(Cursor c, Optional<Tree> definition, List<Tree> decls) {
+        this(c, definition, decls, c.spelling());
+    }
+
+    private StructTree(Cursor c, Optional<Tree> definition, List<Tree> decls, String name) {
+        super(c, name);
+        this.definition = c.isDefinition()? Optional.of(this) : Objects.requireNonNull(definition);
+        this.declarations = Collections.unmodifiableList(decls);
+    }
+
+    @Override
+    public StructTree withName(String newName) {
+        return name().equals(newName)? this :
+            new StructTree(cursor(), definition, declarations, newName);
+    }
+
+    public StructTree withNameAndDecls(String newName, List<Tree> newDecls) {
+        return new StructTree(cursor(), definition, newDecls, newName);
+    }
+
+    public Optional<Tree> definition() {
+        return definition;
     }
 
     public List<Tree> declarations() {
@@ -87,6 +109,7 @@
         return cursor().kind() == CursorKind.UnionDecl;
     }
 
+
     /**
      * Is this struct/union declared as anonymous member of another struct/union?
      *
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/Tree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/Tree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -22,18 +22,26 @@
  */
 package com.sun.tools.jextract.tree;
 
+import java.util.Objects;
 import jdk.internal.clang.Cursor;
+import jdk.internal.clang.Type;
 import jdk.internal.clang.SourceLocation;
 import jdk.internal.clang.SourceRange;
-import jdk.internal.clang.Type;
 
 public class Tree {
     private final Cursor c;
-    public Tree(Cursor c) {
-        this.c = c;
+    private final String name;
+
+    Tree(Cursor c) {
+        this(c, c.spelling());
     }
 
-    final Cursor cursor() {
+    Tree(Cursor c, String name) {
+        this.c = Objects.requireNonNull(c);
+        this.name = Objects.requireNonNull(name);
+    }
+
+    public final Cursor cursor() {
         return c;
     }
 
@@ -41,12 +49,12 @@
         return c.type();
     }
 
-    public final String name() {
-        return c.spelling();
+    public Tree withName(String newName) {
+        return name.equals(newName)? this : new Tree(c, newName);
     }
 
-    public final String identifier() {
-        return LayoutUtils.getIdentifier(c);
+    public final String name() {
+        return name;
     }
 
     public final SourceLocation location() {
@@ -87,12 +95,13 @@
             return false;
         }
 
-        return c.equals(((Tree)obj).cursor());
+        Tree t = (Tree)obj;
+        return name.equals(t.name()) && c.equals(t.cursor());
     }
 
     @Override
     public final int hashCode() {
-        return c.hashCode();
+        return name.hashCode() ^ c.hashCode();
     }
 
     @Override
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/TreeMaker.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/TreeMaker.java	Tue Sep 18 19:14:07 2018 +0200
@@ -24,10 +24,13 @@
 
 import java.nio.file.Path;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.ArrayList;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.function.Supplier;
 import java.util.stream.Stream;
 import java.util.stream.Collectors;
 import jdk.internal.clang.Cursor;
@@ -35,8 +38,14 @@
 import jdk.internal.clang.Type;
 
 public class TreeMaker {
+    private final Map<Cursor, Tree> treeCache = new HashMap<>();
+
     public TreeMaker() {}
 
+    private <T extends Tree> T checkCache(Cursor c, Class<T> clazz, Supplier<Tree> factory) {
+        return clazz.cast(treeCache.computeIfAbsent(c, cx->factory.get()));
+    }
+
     public Tree createTree(Cursor c) {
         switch (Objects.requireNonNull(c).kind()) {
             case EnumDecl:
@@ -54,7 +63,7 @@
             case VarDecl:
                 return createVar(c);
             default:
-                return new Tree(c);
+                return checkCache(c, Tree.class, ()->new Tree(c));
         }
     }
 
@@ -75,26 +84,27 @@
     }
 
     private EnumTree createEnumCommon(Cursor c, List<FieldTree> fields) {
-        return new EnumTree(c, fields);
+        Optional<Tree> def = Optional.ofNullable(c.isDefinition()? null : createTree(c.getDefinition()));
+        return checkCache(c, EnumTree.class, ()->new EnumTree(c, def, fields));
     }
 
     public FieldTree createField(Cursor c) {
         checkCursorAny(c, CursorKind.EnumConstantDecl, CursorKind.FieldDecl);
-        return new FieldTree(c);
+        return checkCache(c, FieldTree.class, ()->new FieldTree(c));
     }
 
     public FunctionTree createFunction(Cursor c) {
         checkCursorAny(c, CursorKind.FunctionDecl);
-        return new FunctionTree(c);
+        return checkCache(c, FunctionTree.class, ()->new FunctionTree(c));
     }
 
     public MacroTree createMacro(Cursor c, Optional<Object> value) {
         checkCursorAny(c, CursorKind.MacroDefinition);
-        return new MacroTree(c, value);
+        return checkCache(c, MacroTree.class, ()->new MacroTree(c, value));
     }
 
     public HeaderTree createHeader(Cursor c, Path path, List<Tree> decls) {
-        return new HeaderTree(c, path, decls);
+        return checkCache(c, HeaderTree.class, ()->new HeaderTree(c, path, decls));
     }
 
     public StructTree createStruct(Cursor c) {
@@ -109,17 +119,22 @@
     }
 
     private StructTree createStructCommon(Cursor c, List<Tree> declarations) {
-        return new StructTree(c, declarations);
+        Optional<Tree> def = Optional.ofNullable(c.isDefinition()? null : createTree(c.getDefinition()));
+        return checkCache(c, StructTree.class, ()->new StructTree(c, def, declarations));
     }
 
     public TypedefTree createTypedef(Cursor c) {
         checkCursor(c, CursorKind.TypedefDecl);
-        return new TypedefTree(c);
+        Cursor dcl = c.type().canonicalType().getDeclarationCursor();
+        Optional<Tree> def = Optional.ofNullable(dcl.isDefinition()? createTree(dcl) : null);
+        return checkCache(c, TypedefTree.class, ()->{
+            return new TypedefTree(c, def);
+        });
     }
 
-    public VarTree createVar(Cursor c) {
+    private VarTree createVar(Cursor c) {
         checkCursor(c, CursorKind.VarDecl);
-        return new VarTree(c);
+        return checkCache(c, VarTree.class, ()->new VarTree(c));
     }
 
     private void checkCursor(Cursor c, CursorKind k) {
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/TreePrinter.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/TreePrinter.java	Tue Sep 18 19:14:07 2018 +0200
@@ -23,21 +23,15 @@
 package com.sun.tools.jextract.tree;
 
 import java.util.List;
-import com.sun.tools.jextract.tree.EnumTree;
-import com.sun.tools.jextract.tree.FieldTree;
-import com.sun.tools.jextract.tree.FunctionTree;
-import com.sun.tools.jextract.tree.HeaderTree;
-import com.sun.tools.jextract.tree.MacroTree;
-import com.sun.tools.jextract.tree.SimpleTreeVisitor;
-import com.sun.tools.jextract.tree.StructTree;
-import com.sun.tools.jextract.tree.Tree;
-import com.sun.tools.jextract.tree.TreeMaker;
-import com.sun.tools.jextract.tree.VarTree;
 
 public class TreePrinter extends SimpleTreeVisitor<Void, Void> {
     @Override
     public Void defaultAction(Tree t, Void v) {
         System.out.println(t.getClass().getSimpleName());
+        String name = t.name();
+        if (!name.isEmpty()) {
+            System.out.println("name: " + t.name());
+        }
         System.out.println(t);
         return null;
     }
@@ -53,6 +47,10 @@
                 f.accept(this, v);
             }
         }
+        if (!e.isDefinition() && e.definition().isPresent()) {
+            System.out.println("--> definition");
+            defaultAction(e.definition().get(), v);
+        }
         return null;
     }
 
@@ -75,6 +73,10 @@
     @Override
     public Void visitHeader(HeaderTree t, Void v) {
         System.out.println("HeaderTree @ " + t.path());
+        String name = t.name();
+        if (!name.isEmpty()) {
+            System.out.println("name: " + t.name());
+        }
         int i = 0;
         for (Tree decl : t.declarations()) {
             System.out.println("--> header declaration: " + i++);
@@ -86,7 +88,7 @@
     @Override
     public Void visitStruct(StructTree s, Void v) {
         defaultAction(s, v);
-        System.out.printf("name = '%s', isAnonymous? = %b, layout = %s\n\n",
+        System.out.printf("name = '%s', isAnonumous? = %b, layout = %s\n\n",
             s.name(), s.isAnonymous(), s.layout((ft, l) -> l));
         List<? extends FieldTree> fields = s.fields();
         if (! fields.isEmpty()) {
@@ -102,6 +104,10 @@
                 nt.accept(this, v);
             }
         }
+        if (!s.isDefinition() && s.definition().isPresent()) {
+            System.out.println("--> definition");
+            defaultAction(s.definition().get(), v);
+        }
         return null;
     }
 
@@ -111,4 +117,14 @@
         System.out.printf("%s layout = %s\n\n", t.name(), t.layout());
         return null;
     }
+
+    @Override
+    public Void visitTypedef(TypedefTree t, Void v) {
+        defaultAction(t, v);
+        if (t.typeDefinition().isPresent()) {
+            System.out.println("--> type definition");
+            defaultAction(t.typeDefinition().get(), v);
+        }
+        return null;
+    }
 }
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/TypedefTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/TypedefTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -22,11 +22,30 @@
  */
 package com.sun.tools.jextract.tree;
 
+import java.util.Optional;
+import java.util.Objects;
 import jdk.internal.clang.Cursor;
 
 public class TypedefTree extends Tree {
-    public TypedefTree(Cursor c) {
-        super(c);
+    private final Optional<Tree> typeDefinition;
+
+    TypedefTree(Cursor c, Optional<Tree> definition) {
+        this(c, definition, c.spelling());
+    }
+
+    private TypedefTree(Cursor c, Optional<Tree> definition, String name) {
+        super(c, name);
+        this.typeDefinition = Objects.requireNonNull(definition);
+    }
+
+    @Override
+    public TypedefTree withName(String newName) {
+        return name().equals(newName)? this :
+            new TypedefTree(cursor(), typeDefinition, newName);
+    }
+
+    public Optional<Tree> typeDefinition() {
+        return typeDefinition;
     }
 
     @Override
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/VarTree.java	Mon Sep 17 23:29:24 2018 +0200
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/tree/VarTree.java	Tue Sep 18 19:14:07 2018 +0200
@@ -26,8 +26,17 @@
 import jdk.internal.clang.Cursor;
 
 public class VarTree extends Tree {
-    public VarTree(Cursor c) {
-        super(c);
+    VarTree(Cursor c) {
+        this(c, c.spelling());
+    }
+
+    private VarTree(Cursor c, String name) {
+        super(c, name);
+    }
+
+    @Override
+    public VarTree withName(String newName) {
+        return name().equals(newName)? this : new VarTree(cursor(), newName);
     }
 
     @Override