private static boolean inputFilesUnderSymlink( // We use Collection<Path> instead of Iterable<Path> to prevent // accidentally passing in Path, since Path itself is Iterable<Path>. Collection<Path> inputs, ProjectFilesystem projectFilesystem, Map<Path, Path> symlinkExistenceCache, Map<Path, Path> newSymlinksEncountered) throws IOException { boolean result = false; for (Path input : inputs) { for (int i = 1; i < input.getNameCount(); i++) { Path subpath = input.subpath(0, i); Path resolvedSymlink = symlinkExistenceCache.get(subpath); if (resolvedSymlink != null) { LOG.debug("Detected cached symlink %s -> %s", subpath, resolvedSymlink); newSymlinksEncountered.put(subpath, resolvedSymlink); result = true; } else if (projectFilesystem.isSymLink(subpath)) { Path symlinkTarget = projectFilesystem.resolve(subpath).toRealPath(); Path relativeSymlinkTarget = projectFilesystem.getPathRelativeToProjectRoot(symlinkTarget).or(symlinkTarget); LOG.debug("Detected symbolic link %s -> %s", subpath, relativeSymlinkTarget); newSymlinksEncountered.put(subpath, relativeSymlinkTarget); symlinkExistenceCache.put(subpath, relativeSymlinkTarget); result = true; } } } return result; }