Skip to content

Commit

Permalink
Fork annotation processing into its own step.
Browse files Browse the repository at this point in the history
This is part of a refactor to gather all the GenerationUnits before processing begins.

The commented out lines in J2ObjCTest.java succeed on Mac, but mysteriously the annotation processing fails on my PC and in []. The same annotation processing (with precisely the same args) succeeds when run with Javac on PC. The same result happens when only this test is patched against head. Per tball, proceeding and circling back later since nothing in annotation processing is broken now that wasn't broken before.
	Change on 2015/03/03 by mthvedt <mthvedt@google.com>
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=87660001
  • Loading branch information
mthvedt authored and kstanger committed Mar 18, 2015
1 parent 021cd16 commit 97be5e9
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 132 deletions.
@@ -0,0 +1,142 @@
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.devtools.j2objc;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.devtools.j2objc.file.InputFile;
import com.google.devtools.j2objc.file.RegularInputFile;
import com.google.devtools.j2objc.util.ErrorUtil;
import com.google.devtools.j2objc.util.FileUtil;
import com.google.devtools.j2objc.util.PathClassLoader;

import org.eclipse.jdt.core.compiler.batch.BatchCompiler;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;

import javax.annotation.processing.Processor;

/**
* Preprocesses all input with annotation processors, if any.
*/
class AnnotationPreProcessor {

private File tmpDirectory;
private List<RegularInputFile> additionalFiles = new ArrayList<RegularInputFile>();

AnnotationPreProcessor() {
}

List<RegularInputFile> getAdditionalFiles() {
return additionalFiles;
}

File getTemporaryDirectory() {
return tmpDirectory;
}

/**
* Process the given input files, given in the same format as J2ObjC command line args.
*/
void process(Iterable<String> fileArgs) {
assert tmpDirectory == null; // Shouldn't run an instance more than once.

if (!hasAnnotationProcessors()) {
return;
}

try {
tmpDirectory = FileUtil.createTempDir("annotations");
} catch (IOException e) {
ErrorUtil.error("failed creating temporary directory: " + e);
return;
}
String tmpDirPath = tmpDirectory.getAbsolutePath();
List<String> compileArgs = Lists.newArrayList();
Joiner pathJoiner = Joiner.on(":");
List<String> sourcePath = Options.getSourcePathEntries();
sourcePath.add(tmpDirPath);
compileArgs.add("-sourcepath");
compileArgs.add(pathJoiner.join(sourcePath));
compileArgs.add("-classpath");
List<String> classPath = Options.getClassPathEntries();
compileArgs.add(pathJoiner.join(classPath));
compileArgs.add("-encoding");
compileArgs.add(Options.getCharset().name());
compileArgs.add("-source");
compileArgs.add("1.7");
compileArgs.add("-s");
compileArgs.add(tmpDirPath);
compileArgs.add("-d");
compileArgs.add(tmpDirPath);
if (Options.isVerbose()) {
compileArgs.add("-XprintProcessorInfo");
compileArgs.add("-XprintRounds");
}
for (String fileArg : fileArgs) {
compileArgs.add(fileArg);
}
Map<String, String> batchOptions = Maps.newHashMap();
batchOptions.put(CompilerOptions.OPTION_Process_Annotations, CompilerOptions.ENABLED);
batchOptions.put(CompilerOptions.OPTION_GenerateClassFiles, CompilerOptions.DISABLED);
// Fully qualified name used since "Main" isn't unique.
org.eclipse.jdt.internal.compiler.batch.Main batchCompiler =
new org.eclipse.jdt.internal.compiler.batch.Main(
new PrintWriter(System.out), new PrintWriter(System.err), false, batchOptions, null);
if (!batchCompiler.compile(compileArgs.toArray(new String[0]))) {
// Any compilation errors will already by displayed.
ErrorUtil.error("failed batch processing sources");
} else {
addGeneratedSources(tmpDirectory, "");
}
}

/**
* Check whether any javax.annotation.processing.Processor services are defined on
* the declared classpath. This is checked here to avoid batch compiling sources
* in case any might have annotations that should be processed.
*/
private boolean hasAnnotationProcessors() {
ServiceLoader<Processor> serviceLoader = ServiceLoader.load(
Processor.class, new PathClassLoader(Options.getClassPathEntries()));
Iterator<Processor> iterator = serviceLoader.iterator();
return iterator.hasNext();
}

private void addGeneratedSources(File dir, String currentRelativePath) {
assert dir.exists() && dir.isDirectory();
for (File f : dir.listFiles()) {
String relativeName = currentRelativePath + File.separatorChar + f.getName();
if (f.isDirectory()) {
addGeneratedSources(f, relativeName);
} else {
if (f.getName().endsWith(".java")) {
additionalFiles.add(new RegularInputFile(f.getPath(), relativeName));
}
}
}
}
}
18 changes: 17 additions & 1 deletion translator/src/main/java/com/google/devtools/j2objc/J2ObjC.java
Expand Up @@ -18,9 +18,11 @@

import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.Files;
import com.google.devtools.j2objc.file.InputFile;
import com.google.devtools.j2objc.types.Types;
import com.google.devtools.j2objc.util.DeadCodeMap;
import com.google.devtools.j2objc.util.ErrorUtil;
import com.google.devtools.j2objc.util.FileUtil;
import com.google.devtools.j2objc.util.JdtParser;
import com.google.devtools.j2objc.util.NameTable;
import com.google.devtools.j2objc.util.PathClassLoader;
Expand All @@ -35,7 +37,6 @@
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
Expand Down Expand Up @@ -146,9 +147,20 @@ private static DeadCodeMap loadDeadCodeMap() {
* @param fileArgs the files to process, same format as command-line args to {@link #main}.
*/
public static void run(List<String> fileArgs) {
File preProcessorTempDir = null;
try {
JdtParser parser = createParser();

AnnotationPreProcessor preProcessor = new AnnotationPreProcessor();
preProcessor.process(fileArgs);
preProcessorTempDir = preProcessor.getTemporaryDirectory();
if (ErrorUtil.errorCount() > 0) {
return;
}
if (preProcessorTempDir != null) {
parser.addSourcepathEntry(preProcessorTempDir.getAbsolutePath());
}

PackageInfoPreProcessor packageInfoPreProcessor = new PackageInfoPreProcessor(parser);
packageInfoPreProcessor.processFiles(fileArgs);
if (ErrorUtil.errorCount() > 0) {
Expand All @@ -165,6 +177,7 @@ public static void run(List<String> fileArgs) {

TranslationProcessor translationProcessor
= new TranslationProcessor(parser, loadDeadCodeMap());
translationProcessor.pendingFiles.addAll(preProcessor.getAdditionalFiles());
translationProcessor.processFiles(fileArgs);
if (ErrorUtil.errorCount() > 0) {
return;
Expand All @@ -173,6 +186,9 @@ public static void run(List<String> fileArgs) {
} finally {
NameTable.cleanup();
Types.cleanup();
if (preProcessorTempDir != null) {
FileUtil.deleteTempDir(preProcessorTempDir);
}
Options.deleteTemporaryDirectory();
}
}
Expand Down
Expand Up @@ -651,13 +651,15 @@ public static void deleteTemporaryDirectory() {
}
}

private static void deleteDir(File dir) {
static void deleteDir(File dir) {
for (File f : dir.listFiles()) {
if (f.isDirectory()) {
deleteDir(f);
} else if (f.getName().endsWith(".java")) {
// Only delete Java files, as other temporary files (like hsperfdata)
// may also be in tmpdir.
// TODO(kstanger): It doesn't make sense that hsperfdata would show up in our tempdir.
// Consider deleting this method and using FileUtil#deleteTempDir() instead.
f.delete();
}
}
Expand Down
Expand Up @@ -14,15 +14,11 @@

package com.google.devtools.j2objc;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.devtools.j2objc.ast.CompilationUnit;
import com.google.devtools.j2objc.ast.PackageDeclaration;
import com.google.devtools.j2objc.ast.TreeConverter;
import com.google.devtools.j2objc.file.InputFile;
import com.google.devtools.j2objc.file.RegularInputFile;
import com.google.devtools.j2objc.gen.GenerationUnit;
import com.google.devtools.j2objc.gen.ObjectiveCHeaderGenerator;
import com.google.devtools.j2objc.gen.ObjectiveCImplementationGenerator;
Expand Down Expand Up @@ -64,11 +60,9 @@
import com.google.devtools.j2objc.util.FileUtil;
import com.google.devtools.j2objc.util.JdtParser;
import com.google.devtools.j2objc.util.NameTable;
import com.google.devtools.j2objc.util.PathClassLoader;
import com.google.devtools.j2objc.util.TimeTracker;

import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;

import java.io.File;
import java.io.FileNotFoundException;
Expand All @@ -77,17 +71,14 @@
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Queue;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.annotation.processing.Processor;

/**
* Processes source files by translating each source into an Objective-C header
Expand Down Expand Up @@ -137,10 +128,6 @@ public TranslationProcessor(JdtParser parser, DeadCodeMap deadCodeMap) {

@Override
public void processFiles(Iterable<String> files) {
if (hasAnnotationProcessors()) {
processAnnotations(files);
}

loadHeaderMappings();

if (ErrorUtil.errorCount() > 0) {
Expand All @@ -157,76 +144,6 @@ public void processFiles(Iterable<String> files) {
}
}

private void processAnnotations(Iterable<String> files) {
File tmpDirectory;
try {
tmpDirectory = createTmpDir();
} catch (IOException e) {
ErrorUtil.error("failed creating temporary directory: " + e);
return;
}
String tmpDirPath = tmpDirectory.getAbsolutePath();
List<String> compileArgs = Lists.newArrayList();
Joiner pathJoiner = Joiner.on(":");
List<String> sourcePath = Options.getSourcePathEntries();
sourcePath.add(tmpDirPath);
compileArgs.add("-sourcepath");
compileArgs.add(pathJoiner.join(sourcePath));
compileArgs.add("-classpath");
List<String> classPath = Options.getClassPathEntries();
compileArgs.add(pathJoiner.join(classPath));
compileArgs.add("-encoding");
compileArgs.add(Options.getCharset().name());
compileArgs.add("-source");
compileArgs.add("1.7");
compileArgs.add("-s");
compileArgs.add(tmpDirPath);
if (Options.isVerbose()) {
compileArgs.add("-XprintProcessorInfo");
}
for (String file : files) {
compileArgs.add(file);
}
Map<String, String> batchOptions = Maps.newHashMap();
batchOptions.put(CompilerOptions.OPTION_Process_Annotations, CompilerOptions.ENABLED);
batchOptions.put(CompilerOptions.OPTION_GenerateClassFiles, CompilerOptions.DISABLED);
// Fully qualified name used since "Main" isn't descriptive.
org.eclipse.jdt.internal.compiler.batch.Main batchCompiler =
new org.eclipse.jdt.internal.compiler.batch.Main(
new PrintWriter(System.out), new PrintWriter(System.err), false, batchOptions, null);
if (!batchCompiler.compile(compileArgs.toArray(new String[0]))) {
// Any compilation errors will already by displayed.
ErrorUtil.error("failed batch processing sources");
} else {
getParser().addSourcepathEntry(tmpDirPath);
addGeneratedSources(tmpDirectory, "");
}
}

private static File createTmpDir() throws IOException {
File tmpDirectory = new File("/tmp/annotation_processing");
if (!tmpDirectory.mkdir() && !tmpDirectory.exists()) {
File tmpRoot = File.createTempFile("foo", "bar").getParentFile();
tmpDirectory = new File(tmpRoot, "annotation_processing");
tmpDirectory.mkdir();
}
return tmpDirectory;
}

private void addGeneratedSources(File dir, String currentRelativePath) {
assert dir.exists() && dir.isDirectory();
for (File f : dir.listFiles()) {
String relativeName = currentRelativePath + File.separatorChar + f.getName();
if (f.isDirectory()) {
addGeneratedSources(f, relativeName);
} else {
if (f.getName().endsWith(".java")) {
pendingFiles.add(new RegularInputFile(f.getPath(), relativeName));
}
}
}
}

@Override
protected void processSource(InputFile file, String source) {
if (logger.isLoggable(Level.INFO)) {
Expand Down Expand Up @@ -616,16 +533,4 @@ static void loadHeaderMappings() {
}
}
}

/**
* Check whether any javax.annotation.processing.Processor services are defined on
* the declared classpath. This is checked here to avoid batch compiling sources
* in case any might have annotations that should be processed.
*/
private boolean hasAnnotationProcessors() {
ServiceLoader<Processor> serviceLoader = ServiceLoader.load(
Processor.class, new PathClassLoader(Options.getClassPathEntries()));
Iterator<Processor> iterator = serviceLoader.iterator();
return iterator.hasNext();
}
}

0 comments on commit 97be5e9

Please sign in to comment.