< prev index next >

src/jdk.jextract/share/classes/com/sun/tools/jextract/Context.java

Print this page




  27 import java.io.File;
  28 import java.io.IOException;
  29 import java.io.PrintWriter;
  30 import java.io.OutputStream;
  31 import java.io.UncheckedIOException;
  32 import java.nicl.Library;
  33 import java.nio.file.Files;
  34 import java.nio.file.Path;
  35 import java.util.*;
  36 import java.util.function.Function;
  37 import java.util.jar.JarOutputStream;
  38 import java.util.logging.Logger;
  39 import java.util.zip.ZipEntry;
  40 import jdk.internal.nicl.NativeLibraryImpl;
  41 
  42 import static java.nio.file.StandardOpenOption.*;
  43 
  44 /**
  45  * The setup for the tool execution
  46  */
  47 public class Context {


  48     // The folder path mapping to package name
  49     private final Map<Path, String> pkgMap;
  50     // The header file parsed
  51     private final Map<Path, HeaderFile> headerMap;
  52     // The args for parsing C
  53     final List<String> clangArgs;
  54     // The set of source header files
  55     final Set<Path>  sources;
  56     // The list of library names
  57     final List<String> libraryNames;
  58     // The list of library paths
  59     final List<String> libraryPaths;
  60     // The list of library paths for link checks
  61     final List<String> linkCheckPaths;
  62 
  63     final PrintWriter out;
  64     final PrintWriter err;
  65 
  66     // check if a symbol is found in any of the libraries or not.
  67     public static interface SymbolChecker {
  68         public boolean lookup(String name);
  69     }
  70 
  71     SymbolChecker symChecker;
  72 
  73     final static String defaultPkg = "jextract.dump";
  74     private static Context instance;
  75     public final Logger logger = Logger.getLogger(getClass().getPackage().getName());
  76 
  77     private Context(PrintWriter out, PrintWriter err) {

  78         this.pkgMap = new HashMap<>();
  79         this.headerMap = new HashMap<>();
  80         this.clangArgs = new ArrayList<>();
  81         this.sources = new TreeSet<>();
  82         this.libraryNames = new ArrayList<>();
  83         this.libraryPaths = new ArrayList<>();
  84         this.linkCheckPaths = new ArrayList<>();
  85         this.out = out;
  86         this.err = err;
  87     }
  88 
  89     // used by jtreg tests
  90     public static Context newInstance() {
  91         return newInstance(new PrintWriter(System.out, true), new PrintWriter(System.err, true));
  92     }
  93 
  94     static Context newInstance(PrintWriter out, PrintWriter err) {
  95         return instance = new Context(out, err);
  96     }
  97 
  98     static Context getInstance() {
  99         return instance;
 100     }
 101 
 102     public void addSource(Path path) {
 103         sources.add(path);
 104     }
 105 












 106     /**
 107      * Setup a package name for a given folder.
 108      *
 109      * @param folder The path to the folder, use null to set catch-all.
 110      * @param pkg    The package name
 111      * @return True if the folder is setup successfully. False is a package
 112      * has been assigned for the folder.
 113      */
 114     public boolean usePackageForFolder(Path folder, String pkg) {
 115         if (folder != null) {
 116             folder = folder.toAbsolutePath();
 117             if (!Files.isDirectory(folder)) {
 118                 folder = folder.getParent();
 119             }
 120         }
 121         String existing = pkgMap.putIfAbsent(folder, pkg);
 122         final String finalFolder = (null == folder) ? "all folders not configured" : folder.toString();
 123         if (null == existing) {
 124             logger.config(() -> "Package " + pkg + " is selected for " + finalFolder);
 125             return true;
 126         } else {
 127             logger.warning(() -> "Package " + existing + " had been selected for " + finalFolder + ", request to use " + pkg + " is ignored.");
 128             return false;
 129         }
 130     }
 131 
 132     public static class Entity {
 133         public final String pkg;
 134         public final String entity;
 135 
 136         Entity(String pkg, String entity) {
 137             this.pkg = pkg;
 138             this.entity = entity;
 139         }
 140     }
 141 
 142     /**
 143      * Determine package and interface name given a path. If the path is
 144      * a folder, then only package name is determined. The package name is
 145      * determined with the longest path matching the setup. If the path is not
 146      * setup for any package, the default package name is returned.
 147      *
 148      * @param origin The source path
 149      * @return The Entity
 150      * @see Context::usePackageForFolder(Path, String)
 151      */
 152     public Entity whatis(Path origin) {
 153         // normalize to absolute path
 154         origin = origin.toAbsolutePath();
 155         String filename = null;
 156         if (!Files.isDirectory(origin)) {
 157             // ensure it's a folder name
 158             filename = origin.getFileName().toString();
 159             origin = origin.getParent();
 160         }
 161         Path path = origin;
 162 
 163         // search the map for a hit with longest path
 164         while (path != null && !pkgMap.containsKey(path)) {
 165             path = path.getParent();
 166         }
 167 
 168         int start;
 169         String pkg;
 170         if (path != null) {
 171             start = path.getNameCount();
 172             pkg = pkgMap.get(path);


 190             sb.append(Utils.toJavaIdentifier(origin.getName(start++).toString()));
 191             sb.append("_");
 192         }
 193 
 194         int ext = filename.lastIndexOf('.');
 195         if (ext != -1) {
 196             sb.append(filename.substring(0, ext));
 197         } else {
 198             sb.append(filename);
 199         }
 200         return new Entity(pkg, Utils.toClassName(sb.toString()));
 201     }
 202 
 203     HeaderFile getHeaderFile(Path header, HeaderFile main) {
 204         if (!Files.isRegularFile(header)) {
 205             logger.warning(() -> "Not a regular file: " + header.toString());
 206             throw new IllegalArgumentException(header.toString());
 207         }
 208 
 209         final Context.Entity e = whatis(header);
 210         return new HeaderFile(header, e.pkg, e.entity, main, symChecker);
 211     }
 212 
 213     void processCursor(Cursor c, HeaderFile main, Function<HeaderFile, CodeFactory> fn) {
 214         SourceLocation loc = c.getSourceLocation();
 215         if (loc == null) {
 216             logger.info(() -> "Ignore Cursor " + c.spelling() + "@" + c.USR() + " has no SourceLocation");
 217             return;
 218         }
 219         logger.fine(() -> "Do cursor: " + c.spelling() + "@" + c.USR());
 220 
 221         HeaderFile header;
 222         boolean isBuiltIn = false;
 223 
 224         if (loc.isFromMainFile()) {
 225             header = main;
 226         } else {
 227             SourceLocation.Location src = loc.getFileLocation();
 228             if (src == null) {
 229                 logger.info(() -> "Cursor " + c.spelling() + "@" + c.USR() + " has no FileLocation");
 230                 return;


 239                 p = p.normalize().toAbsolutePath();
 240                 header = headerMap.get(p);
 241                 if (header == null) {
 242                     final HeaderFile hf = header = getHeaderFile(p, main);
 243                     logger.config(() -> "First encounter of header file " + hf.path + ", assigned to package " + hf.pkgName);
 244                     // Only generate code for header files sepcified or in the same package
 245                     // System headers are excluded, they need to be explicitly specified in jextract cmdline
 246                     if (sources.contains(p) ||
 247                         (!loc.isInSystemHeader()) && (header.pkgName.equals(main.pkgName))) {
 248                         logger.config("Code gen for header " + p + " enabled in package " + header.pkgName);
 249                         header.useCodeFactory(fn.apply(header));
 250                     }
 251                     headerMap.put(p, header);
 252                 }
 253             }
 254         }
 255 
 256         header.processCursor(c, main, isBuiltIn);
 257     }
 258 




 259     public void parse(Function<HeaderFile, CodeFactory> fn) {
 260         if (!libraryNames.isEmpty() && !linkCheckPaths.isEmpty()) {
 261             Library[] libs = NativeLibraryImpl.loadLibraries(
 262                 linkCheckPaths.toArray(new String[0]),
 263                 libraryNames.toArray(new String[0]));
 264 
 265             // check if the given symbol is found in any of the libraries or not.
 266             // If not found, warn the user for the missing symbol.
 267             symChecker = name -> {
 268                 if (Main.DEBUG) {
 269                     err.println("Searching symbol: " + name);
 270                 }
 271                 return (Arrays.stream(libs).filter(lib -> {
 272                         try {
 273                             lib.lookup(name);
 274                             if (Main.DEBUG) {
 275                                 err.println("Found symbol: " + name);
 276                             }
 277                             return true;
 278                         } catch (NoSuchMethodException nsme) {


 301                         err.println(d);
 302                         if (d.severity() >  Diagnostic.CXDiagnostic_Warning) {
 303                             throw new RuntimeException(d.toString());
 304                         }
 305                     },
 306                     Main.INCLUDE_MACROS,
 307                     clangArgs.toArray(new String[0]));
 308 
 309             tuCursor.children()
 310                     .peek(c -> logger.finest(
 311                         () -> "Cursor: " + c.spelling() + "@" + c.USR() + "?" + c.isDeclaration()))
 312                     .filter(c -> c.isDeclaration() || c.isPreprocessing())
 313                     .forEach(c -> processCursor(c, hf, fn));
 314         });
 315     }
 316 
 317     private Map<String, List<CodeFactory>> getPkgCfMap() {
 318         final Map<String, List<CodeFactory>> mapPkgCf = new HashMap<>();
 319         // Build the pkg to CodeFactory map
 320         headerMap.values().forEach(header -> {
 321             CodeFactory cf = header.cf;
 322             String pkg = header.pkgName;
 323             logger.config(() -> "File " + header + " is in package: " + pkg);
 324             if (cf == null) {
 325                 logger.config(() -> "File " + header + " code generation is not activated!");
 326                 return;
 327             }
 328             List<CodeFactory> l = mapPkgCf.computeIfAbsent(pkg, k -> new ArrayList<>());
 329             l.add(cf);
 330             logger.config(() -> "Add cf " + cf + " to pkg " + pkg + ", size is now " + l.size());
 331         });
 332         return Collections.unmodifiableMap(mapPkgCf);
 333     }
 334 
 335     public Map<String, byte[]> collectClasses(String... pkgs) {
 336         final Map<String, byte[]> rv = new HashMap<>();
 337         final Map<String, List<CodeFactory>> mapPkgCf = getPkgCfMap();
 338         for (String pkg_name : pkgs) {
 339             mapPkgCf.getOrDefault(pkg_name, Collections.emptyList())
 340                     .forEach(cf -> rv.putAll(cf.collect()));
 341         }


 359     public void collectJarFile(final JarOutputStream jos, String... pkgs) {
 360         final Map<String, List<CodeFactory>> mapPkgCf = getPkgCfMap();
 361 
 362         for (String pkg_name : pkgs) {
 363             // convert '.' to '/' to use as a path
 364             String entryName = Utils.toInternalName(pkg_name, "");
 365             // package folder
 366             if (!entryName.isEmpty()) {
 367                 try {
 368                     jos.putNextEntry(new ZipEntry(entryName));
 369                 } catch (IOException ex) {
 370                     throw new UncheckedIOException(ex);
 371                 }
 372             }
 373             logger.fine(() -> "Produce for package " + pkg_name);
 374             mapPkgCf.getOrDefault(pkg_name, Collections.emptyList())
 375                     .forEach(cf -> writeJar(cf, jos));
 376         }
 377     }
 378 
 379     public void collectJarFile(final Path jar, String... pkgs) throws IOException {
 380         logger.info(() -> "Collecting jar file " + jar);
 381         try (OutputStream os = Files.newOutputStream(jar, CREATE, TRUNCATE_EXISTING, WRITE);
 382              JarOutputStream jo = new JarOutputStream(os)) {
 383             collectJarFile(jo, pkgs);
 384         } catch (UncheckedIOException uioe) {
 385             throw uioe.getCause();
 386         }
 387     }
 388 
 389     /**
 390      * Perform a local lookup, any undefined type will cause a JType
 391      * be defined within origin scope.
 392      *
 393      * @param type   The libclang type
 394      * @param origin The path of the file where type is encountered
 395      * @return The JType
 396      */
 397     JType getJType(final Type type, Path origin) {
 398         Path p = origin.normalize().toAbsolutePath();
 399 
 400         HeaderFile hf = headerMap.get(p);
 401         // We should not encounter a type if the header file reference to it is not yet processed
 402         assert(null != hf);
 403         if (hf == null) {
 404             throw new IllegalArgumentException("Failed to lookup header for " + p + " (origin: " + origin + ")");
 405         }
 406 
 407         return hf.localLookup(type);
 408     }
 409 
 410     /**
 411      * Perform a global lookup
 412      *
 413      * @param c The cursor define or declare the type.
 414      * @return
 415      */
 416     public JType getJType(final Cursor c) {
 417         if (c.isInvalid()) {
 418             throw new IllegalArgumentException();
 419         }
 420         SourceLocation loc = c.getSourceLocation();
 421         if (null == loc) {
 422             return null;
 423         }
 424         Path p = loc.getFileLocation().path();
 425         if (null == p) {
 426             return null;
 427         }
 428         return getJType(c.type(), p);
 429     }
 430 }


  27 import java.io.File;
  28 import java.io.IOException;
  29 import java.io.PrintWriter;
  30 import java.io.OutputStream;
  31 import java.io.UncheckedIOException;
  32 import java.nicl.Library;
  33 import java.nio.file.Files;
  34 import java.nio.file.Path;
  35 import java.util.*;
  36 import java.util.function.Function;
  37 import java.util.jar.JarOutputStream;
  38 import java.util.logging.Logger;
  39 import java.util.zip.ZipEntry;
  40 import jdk.internal.nicl.NativeLibraryImpl;
  41 
  42 import static java.nio.file.StandardOpenOption.*;
  43 
  44 /**
  45  * The setup for the tool execution
  46  */
  47 public final class Context {
  48     // package name to TypeDictionary
  49     private final Map<String, TypeDictionary> tdMap;
  50     // The folder path mapping to package name
  51     private final Map<Path, String> pkgMap;
  52     // The header file parsed
  53     private final Map<Path, HeaderFile> headerMap;
  54     // The args for parsing C
  55     private final List<String> clangArgs;
  56     // The set of source header files
  57     private final Set<Path>  sources;
  58     // The list of library names
  59     private final List<String> libraryNames;
  60     // The list of library paths
  61     private final List<String> libraryPaths;
  62     // The list of library paths for link checks
  63     private final List<String> linkCheckPaths;
  64 
  65     final PrintWriter out;
  66     final PrintWriter err;
  67 
  68     // check if a symbol is found in any of the libraries or not.
  69     static interface SymbolChecker {
  70         public boolean lookup(String name);
  71     }
  72 
  73     private SymbolChecker symChecker;
  74 
  75     private final static String defaultPkg = "jextract.dump";
  76     final Logger logger = Logger.getLogger(getClass().getPackage().getName());

  77 
  78     public Context(PrintWriter out, PrintWriter err) {
  79         this.tdMap = new HashMap<>();
  80         this.pkgMap = new HashMap<>();
  81         this.headerMap = new HashMap<>();
  82         this.clangArgs = new ArrayList<>();
  83         this.sources = new TreeSet<>();
  84         this.libraryNames = new ArrayList<>();
  85         this.libraryPaths = new ArrayList<>();
  86         this.linkCheckPaths = new ArrayList<>();
  87         this.out = out;
  88         this.err = err;
  89     }
  90 
  91     public Context() {
  92         this(new PrintWriter(System.out, true), new PrintWriter(System.err, true));

  93     }
  94 
  95     TypeDictionary typeDictionaryFor(String pkg) {
  96         return tdMap.computeIfAbsent(pkg, p->new TypeDictionary(this, p));
  97     }
  98 
  99     void addClangArg(String arg) {
 100         clangArgs.add(arg);
 101     }
 102 
 103     public void addSource(Path path) {
 104         sources.add(path);
 105     }
 106 
 107     void addLibraryName(String name) {
 108         libraryNames.add(name);
 109     }
 110 
 111     void addLibraryPath(String path) {
 112         libraryPaths.add(path);
 113     }
 114 
 115     void addLinkCheckPath(String path) {
 116         linkCheckPaths.add(path);
 117     }
 118 
 119     /**
 120      * Setup a package name for a given folder.
 121      *
 122      * @param folder The path to the folder, use null to set catch-all.
 123      * @param pkg    The package name
 124      * @return True if the folder is setup successfully. False is a package
 125      * has been assigned for the folder.
 126      */
 127     public boolean usePackageForFolder(Path folder, String pkg) {
 128         if (folder != null) {
 129             folder = folder.toAbsolutePath();
 130             if (!Files.isDirectory(folder)) {
 131                 folder = folder.getParent();
 132             }
 133         }
 134         String existing = pkgMap.putIfAbsent(folder, pkg);
 135         final String finalFolder = (null == folder) ? "all folders not configured" : folder.toString();
 136         if (null == existing) {
 137             logger.config(() -> "Package " + pkg + " is selected for " + finalFolder);
 138             return true;
 139         } else {
 140             logger.warning(() -> "Package " + existing + " had been selected for " + finalFolder + ", request to use " + pkg + " is ignored.");
 141             return false;
 142         }
 143     }
 144 
 145     static class Entity {
 146         final String pkg;
 147         final String entity;
 148 
 149         Entity(String pkg, String entity) {
 150             this.pkg = pkg;
 151             this.entity = entity;
 152         }
 153     }
 154 
 155     /**
 156      * Determine package and interface name given a path. If the path is
 157      * a folder, then only package name is determined. The package name is
 158      * determined with the longest path matching the setup. If the path is not
 159      * setup for any package, the default package name is returned.
 160      *
 161      * @param origin The source path
 162      * @return The Entity
 163      * @see Context::usePackageForFolder(Path, String)
 164      */
 165     Entity whatis(Path origin) {
 166         // normalize to absolute path
 167         origin = origin.toAbsolutePath();
 168         String filename = null;
 169         if (!Files.isDirectory(origin)) {
 170             // ensure it's a folder name
 171             filename = origin.getFileName().toString();
 172             origin = origin.getParent();
 173         }
 174         Path path = origin;
 175 
 176         // search the map for a hit with longest path
 177         while (path != null && !pkgMap.containsKey(path)) {
 178             path = path.getParent();
 179         }
 180 
 181         int start;
 182         String pkg;
 183         if (path != null) {
 184             start = path.getNameCount();
 185             pkg = pkgMap.get(path);


 203             sb.append(Utils.toJavaIdentifier(origin.getName(start++).toString()));
 204             sb.append("_");
 205         }
 206 
 207         int ext = filename.lastIndexOf('.');
 208         if (ext != -1) {
 209             sb.append(filename.substring(0, ext));
 210         } else {
 211             sb.append(filename);
 212         }
 213         return new Entity(pkg, Utils.toClassName(sb.toString()));
 214     }
 215 
 216     HeaderFile getHeaderFile(Path header, HeaderFile main) {
 217         if (!Files.isRegularFile(header)) {
 218             logger.warning(() -> "Not a regular file: " + header.toString());
 219             throw new IllegalArgumentException(header.toString());
 220         }
 221 
 222         final Context.Entity e = whatis(header);
 223         return new HeaderFile(this, header, e.pkg, e.entity, main, symChecker);
 224     }
 225 
 226     void processCursor(Cursor c, HeaderFile main, Function<HeaderFile, CodeFactory> fn) {
 227         SourceLocation loc = c.getSourceLocation();
 228         if (loc == null) {
 229             logger.info(() -> "Ignore Cursor " + c.spelling() + "@" + c.USR() + " has no SourceLocation");
 230             return;
 231         }
 232         logger.fine(() -> "Do cursor: " + c.spelling() + "@" + c.USR());
 233 
 234         HeaderFile header;
 235         boolean isBuiltIn = false;
 236 
 237         if (loc.isFromMainFile()) {
 238             header = main;
 239         } else {
 240             SourceLocation.Location src = loc.getFileLocation();
 241             if (src == null) {
 242                 logger.info(() -> "Cursor " + c.spelling() + "@" + c.USR() + " has no FileLocation");
 243                 return;


 252                 p = p.normalize().toAbsolutePath();
 253                 header = headerMap.get(p);
 254                 if (header == null) {
 255                     final HeaderFile hf = header = getHeaderFile(p, main);
 256                     logger.config(() -> "First encounter of header file " + hf.path + ", assigned to package " + hf.pkgName);
 257                     // Only generate code for header files sepcified or in the same package
 258                     // System headers are excluded, they need to be explicitly specified in jextract cmdline
 259                     if (sources.contains(p) ||
 260                         (!loc.isInSystemHeader()) && (header.pkgName.equals(main.pkgName))) {
 261                         logger.config("Code gen for header " + p + " enabled in package " + header.pkgName);
 262                         header.useCodeFactory(fn.apply(header));
 263                     }
 264                     headerMap.put(p, header);
 265                 }
 266             }
 267         }
 268 
 269         header.processCursor(c, main, isBuiltIn);
 270     }
 271 
 272     public void parse() {
 273         parse(header -> new AsmCodeFactory(this, header));
 274     }
 275 
 276     public void parse(Function<HeaderFile, CodeFactory> fn) {
 277         if (!libraryNames.isEmpty() && !linkCheckPaths.isEmpty()) {
 278             Library[] libs = NativeLibraryImpl.loadLibraries(
 279                 linkCheckPaths.toArray(new String[0]),
 280                 libraryNames.toArray(new String[0]));
 281 
 282             // check if the given symbol is found in any of the libraries or not.
 283             // If not found, warn the user for the missing symbol.
 284             symChecker = name -> {
 285                 if (Main.DEBUG) {
 286                     err.println("Searching symbol: " + name);
 287                 }
 288                 return (Arrays.stream(libs).filter(lib -> {
 289                         try {
 290                             lib.lookup(name);
 291                             if (Main.DEBUG) {
 292                                 err.println("Found symbol: " + name);
 293                             }
 294                             return true;
 295                         } catch (NoSuchMethodException nsme) {


 318                         err.println(d);
 319                         if (d.severity() >  Diagnostic.CXDiagnostic_Warning) {
 320                             throw new RuntimeException(d.toString());
 321                         }
 322                     },
 323                     Main.INCLUDE_MACROS,
 324                     clangArgs.toArray(new String[0]));
 325 
 326             tuCursor.children()
 327                     .peek(c -> logger.finest(
 328                         () -> "Cursor: " + c.spelling() + "@" + c.USR() + "?" + c.isDeclaration()))
 329                     .filter(c -> c.isDeclaration() || c.isPreprocessing())
 330                     .forEach(c -> processCursor(c, hf, fn));
 331         });
 332     }
 333 
 334     private Map<String, List<CodeFactory>> getPkgCfMap() {
 335         final Map<String, List<CodeFactory>> mapPkgCf = new HashMap<>();
 336         // Build the pkg to CodeFactory map
 337         headerMap.values().forEach(header -> {
 338             CodeFactory cf = header.getCodeFactory();
 339             String pkg = header.pkgName;
 340             logger.config(() -> "File " + header + " is in package: " + pkg);
 341             if (cf == null) {
 342                 logger.config(() -> "File " + header + " code generation is not activated!");
 343                 return;
 344             }
 345             List<CodeFactory> l = mapPkgCf.computeIfAbsent(pkg, k -> new ArrayList<>());
 346             l.add(cf);
 347             logger.config(() -> "Add cf " + cf + " to pkg " + pkg + ", size is now " + l.size());
 348         });
 349         return Collections.unmodifiableMap(mapPkgCf);
 350     }
 351 
 352     public Map<String, byte[]> collectClasses(String... pkgs) {
 353         final Map<String, byte[]> rv = new HashMap<>();
 354         final Map<String, List<CodeFactory>> mapPkgCf = getPkgCfMap();
 355         for (String pkg_name : pkgs) {
 356             mapPkgCf.getOrDefault(pkg_name, Collections.emptyList())
 357                     .forEach(cf -> rv.putAll(cf.collect()));
 358         }


 376     public void collectJarFile(final JarOutputStream jos, String... pkgs) {
 377         final Map<String, List<CodeFactory>> mapPkgCf = getPkgCfMap();
 378 
 379         for (String pkg_name : pkgs) {
 380             // convert '.' to '/' to use as a path
 381             String entryName = Utils.toInternalName(pkg_name, "");
 382             // package folder
 383             if (!entryName.isEmpty()) {
 384                 try {
 385                     jos.putNextEntry(new ZipEntry(entryName));
 386                 } catch (IOException ex) {
 387                     throw new UncheckedIOException(ex);
 388                 }
 389             }
 390             logger.fine(() -> "Produce for package " + pkg_name);
 391             mapPkgCf.getOrDefault(pkg_name, Collections.emptyList())
 392                     .forEach(cf -> writeJar(cf, jos));
 393         }
 394     }
 395 
 396     void collectJarFile(final Path jar, String... pkgs) throws IOException {
 397         logger.info(() -> "Collecting jar file " + jar);
 398         try (OutputStream os = Files.newOutputStream(jar, CREATE, TRUNCATE_EXISTING, WRITE);
 399              JarOutputStream jo = new JarOutputStream(os)) {
 400             collectJarFile(jo, pkgs);
 401         } catch (UncheckedIOException uioe) {
 402             throw uioe.getCause();
 403         }
 404     }
 405 
 406     /**
 407      * Perform a local lookup, any undefined type will cause a JType
 408      * be defined within origin scope.
 409      *
 410      * @param type   The libclang type
 411      * @param origin The path of the file where type is encountered
 412      * @return The JType
 413      */
 414     JType getJType(final Type type, Path origin) {
 415         Path p = origin.normalize().toAbsolutePath();
 416 
 417         HeaderFile hf = headerMap.get(p);
 418         // We should not encounter a type if the header file reference to it is not yet processed
 419         assert(null != hf);
 420         if (hf == null) {
 421             throw new IllegalArgumentException("Failed to lookup header for " + p + " (origin: " + origin + ")");
 422         }
 423 
 424         return hf.localLookup(type);
 425     }
 426 
 427     /**
 428      * Perform a global lookup
 429      *
 430      * @param c The cursor define or declare the type.
 431      * @return
 432      */
 433     JType getJType(final Cursor c) {
 434         if (c.isInvalid()) {
 435             throw new IllegalArgumentException();
 436         }
 437         SourceLocation loc = c.getSourceLocation();
 438         if (null == loc) {
 439             return null;
 440         }
 441         Path p = loc.getFileLocation().path();
 442         if (null == p) {
 443             return null;
 444         }
 445         return getJType(c.type(), p);
 446     }
 447 }
< prev index next >