diff --git a/docs/manual/creating-a-checker.tex b/docs/manual/creating-a-checker.tex index 166d77f01d5c..8767517618b8 100644 --- a/docs/manual/creating-a-checker.tex +++ b/docs/manual/creating-a-checker.tex @@ -1987,6 +1987,11 @@ While creating a stub file, you may find the debugging options described in Section~\ref{stub-troubleshooting} useful. +\item + If you want to use an external annotated JDK .jar file, you can specify it when you run the checker: + \begin{Verbatim} + javac -J-Dchecker.annotated.jdk.jar=/path/to/annotated-jdk.jar -processor ... + \end{Verbatim} \end{itemize} diff --git a/framework/build.gradle b/framework/build.gradle index f6327d3c32d4..6c9c23a84efa 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -104,7 +104,7 @@ task copyAndMinimizeAnnotatedJdkFiles(type: JavaExec, dependsOn: cloneAnnotatedJ dependsOn ':javacutil:jar' dependsOn ':dataflow:jar' def inputDir = "${annotatedJdkHome}/src" - def outputDir = "${buildDir}/generated/resources/annotated-jdk/" + def outputDir = "${buildDir}/generated/annotated-jdk/" description = "Copy annotated JDK files to ${outputDir}. Removes private and package-private methods, method bodies, comments, etc. from the annotated JDK" @@ -119,6 +119,22 @@ task copyAndMinimizeAnnotatedJdkFiles(type: JavaExec, dependsOn: cloneAnnotatedJ args outputDir doFirst { + if (project.hasProperty('annotatedJdkBranch')) { + def repoDir = file(annotatedJdkHome) + exec { + workingDir repoDir + commandLine 'git', 'fetch', '--all', '--tags' + } + exec { + workingDir repoDir + commandLine 'git', 'checkout', project.property('annotatedJdkBranch') + } + exec { + workingDir repoDir + commandLine 'git', 'pull', '--ff-only' + } + } + FileTree tree = fileTree(dir: inputDir) NavigableSet annotatedForFiles = new TreeSet<>(); // Populate `annotatedForFiles`. @@ -145,8 +161,17 @@ task copyAndMinimizeAnnotatedJdkFiles(type: JavaExec, dependsOn: cloneAnnotatedJ } } -sourcesJar.dependsOn(copyAndMinimizeAnnotatedJdkFiles) -processResources.dependsOn(copyAndMinimizeAnnotatedJdkFiles) + +task annotatedJdkJar(type: Jar, dependsOn: copyAndMinimizeAnnotatedJdkFiles, group: 'Build') { + description = 'Packages the generated annotated JDK stubs into annotated-jdk.jar at the repository root' + destinationDirectory = rootProject.layout.projectDirectory.dir("checker/dist"); + archiveFileName = 'annotated-jdk.jar' + from("${buildDir}/generated/annotated-jdk") { + into 'annotated-jdk' + } +} + +processResources.dependsOn(annotatedJdkJar) task allSourcesJar(type: Jar, group: 'Build') { description = 'Creates a sources jar that includes sources for all Checker Framework classes in framework.jar' diff --git a/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileElementTypes.java b/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileElementTypes.java index ebd0c8912375..e190ebe44407 100644 --- a/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileElementTypes.java +++ b/framework/src/main/java/org/checkerframework/framework/stub/AnnotationFileElementTypes.java @@ -857,13 +857,50 @@ private void parseJdkJarEntry(String jarEntryName) { } } + private final URL getAnnotatedJDKResourceURL(String resourcePath) { + try { + URL resourceURL = null; + File externalJdkFile = new File(resourcePath); + if (externalJdkFile.exists()) { + resourceURL = + new URL( + "jar:file:" + + externalJdkFile.getAbsolutePath() + + "!/annotated-jdk"); + } + return resourceURL; + } catch (Exception e) { + if (stubDebug) { + System.out.printf( + "Failed to load external annotated JDK from %s: %s%n", + resourcePath, e.getMessage()); + } + return null; + } + } + /** * Returns a JarURLConnection to "/jdk*". * * @return a JarURLConnection to "/jdk*" */ private JarURLConnection getJarURLConnectionToJdk() { - URL resourceURL = atypeFactory.getClass().getResource("/annotated-jdk"); + // First, try to use the external annotated-jdk.jar file if specified + String pathFromProperty = System.getProperty("checker.annotated.jdk.jar"); + URL resourceURL = getAnnotatedJDKResourceURL(pathFromProperty); + if (resourceURL == null) { + // Get the location of checker.jar + URL location = + atypeFactory.getClass().getProtectionDomain().getCodeSource().getLocation(); + try { + Path checkerDir = Paths.get(location.toURI()).getParent(); + String annotatedJarPath = checkerDir.resolve("annotated-jdk.jar").toString(); + resourceURL = getAnnotatedJDKResourceURL(annotatedJarPath); + } catch (URISyntaxException e) { + throw new BugInCF("Cannot parse URL: " + location.toString(), e); + } + } + JarURLConnection connection; try { connection = (JarURLConnection) resourceURL.openConnection();