com.netflix.java.refactor.ast.AstParser.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-source-refactor Show documentation
Show all versions of java-source-refactor Show documentation
Pluggable and distributed refactoring tool for Java source code
package com.netflix.java.refactor.ast
import com.netflix.java.refactor.CompilationUnit
import com.sun.tools.javac.comp.Check
import com.sun.tools.javac.comp.Enter
import com.sun.tools.javac.main.JavaCompiler
import com.sun.tools.javac.nio.JavacPathFileManager
import com.sun.tools.javac.tree.JCTree
import com.sun.tools.javac.util.Context
import com.sun.tools.javac.util.Log
import org.slf4j.LoggerFactory
import java.io.PrintWriter
import java.io.Writer
import java.nio.charset.Charset
import java.nio.file.Path
import javax.tools.JavaFileManager
import javax.tools.JavaFileObject
import javax.tools.StandardLocation
class AstParser(val classpath: Iterable?) {
val context = Context()
// Both of these must be declared before compiler, so that compiler doesn't attempt to register alternate
// instances with contest
private val mutableLog = MutableSourceMapLog()
private val pfm = JavacPathFileManager(context, true, Charset.defaultCharset())
val compiler = JavaCompiler(context)
private inner class MutableSourceMapLog(): Log(context) {
fun removeFile(file: JavaFileObject) {
sourceMap.remove(file)
}
}
private val logger = LoggerFactory.getLogger(AstParser::class.java)
init {
// otherwise the JavacParser will use EmptyEndPosTable, effectively setting -1 as the end position
// for every tree element
compiler.genEndPos = true
mutableLog.setWriters(PrintWriter(object: Writer() {
override fun write(cbuf: CharArray, off: Int, len: Int) {
logger.debug(String(cbuf.slice(off..(off + len)).toCharArray()))
}
override fun flush() {}
override fun close() {}
}))
}
fun parseFiles(files: Iterable): List {
if(classpath != null) { // override classpath
assert(context.get(JavaFileManager::class.java) === pfm)
pfm.setLocation(StandardLocation.CLASS_PATH, classpath)
}
val fileObjects = pfm.getJavaFileObjects(*files.toList().toTypedArray())
// if we are in a reparsing phase, we want to ensure that the contents of the file get re-read
fileObjects.forEach { pfm.flushCache(it) }
val cus = fileObjects
.map { compiler.parse(it) }
.enterAll()
compiler.attribute(compiler.todo)
return cus
}
fun reparse(cu: CompilationUnit): JCTree.JCCompilationUnit {
// this will cause the new AST to be re-entered and re-attributed
val chk = Check.instance(context)
cu.jcCompilationUnit.defs.filterIsInstance().forEach {
chk.compiled.remove(it.sym.flatname)
}
// otherwise, when the parser attempts to set endPosTable on the DiagnosticSource of this file it will blow up
// because the previous parsing iteration has already set one
mutableLog.removeFile(pfm.getJavaFileObjects(cu.source()).first())
return parseFiles(listOf(cu.source())).first()
}
/**
* Enter symbol definitions into each compilation unit's scope
*/
private fun List.enterAll(): List {
val enter = Enter.instance(context)
val compilationUnits = com.sun.tools.javac.util.List.from(this.toTypedArray())
enter.main(compilationUnits)
return this
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy