Commit 6925171c authored by Lubomir Bulej's avatar Lubomir Bulej

- DislClassFinder: output proper binary names for innner classes

- Document the need for binary names in DiSL-Classes attribute
parent 308c1fd7
......@@ -37,6 +37,7 @@ never forget to clear environment variables as inherited classpath could cause
serious trouble.
The manifest file in the instrumentation jars for each suite will contain an
attribute, DiSL-Classes, listing classes that are used for snippet expansion.
The comma-separated list of classess is generated automatically by the build
system based on the annotations used in the instrumentation classes.
attribute, DiSL-Classes, listing binary names of classes that are used for
snippet expansion. The comma-separated list of classes is generated
automatically by the build system based on snippet-related annotations used in
the instrumentation classes.
......@@ -650,10 +650,10 @@ It is possible to use the \code{disl.py} script to invoke DiSL with user-defined
\item All the instrumentation and the analysis classes must be packed into a single jar~file, including any external libraries used by the analysis.
Such libraries can be added to the jar~file using, for example, the \code{jarjar}\footnote{\url{http://code.google.com/p/jarjar/}} tool.
\item The \code{MANIFEST.MF} file in the \code{META-INF} directory of the jar~file must list fully qualified names of all DiSL instrumentation classes, i.e., classes containing snippets or argument processors.
\item The \code{MANIFEST.MF} file in the \code{META-INF} directory of the jar~file must list fully qualified binary names\footnote{\url{http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html\#jls-13.1}} of all DiSL instrumentation classes, i.e., classes containing snippets or argument processors.
Listing~\ref{lst:example-manifest} shows the manifest file of the included example.
In this case, the instrumentation consists of a single class (i.e., \code{DiSLClass}) that can be found in the default package.
In more complex cases, the \code{DiSL-Classes} attribute will contain a comma-separated list of class names.
In more complex cases, the \code{DiSL-Classes} attribute will contain a comma-separated list of class binary names.
\end{itemize}
Run \code{disl.py -h} for info how to use the script and to list all available parameters.
......
......@@ -28,18 +28,33 @@ import ch.usi.dag.disl.annotation.ProcessAlso;
import ch.usi.dag.disl.annotation.SyntheticLocal;
import ch.usi.dag.util.Sets;
public final class DislClassFinder implements Processor {
private final Set <String> __dislClasses = Sets.newHashSet ();
/**
* Identifies DiSL classes based on the use of DiSL annotations. Only classes
* related to snippet expansion are considered DiSL classes, i.e., classes
* containing DiSL snippets and argument processor classes. Guards are not
* considered DiSL classes.
*
* @author Lubomir Bulej
*/
public final class DislClassFinder implements Processor {
//
// Configuration. Initialized by the init() method.
//
private Messager __messager;
private PrintStream __output;
private String __separator;
private String __effectiveSeparator;
private boolean __forceEol;
//
// State kept between processing rounds.
//
private String __effectiveSeparator;
private final Set <String> __dislClasses = Sets.newHashSet ();
//
private static final String __OPTION_OUTPUT__ = "disl.classfinder.output";
......@@ -64,6 +79,7 @@ public final class DislClassFinder implements Processor {
@Override
public Set <String> getSupportedAnnotationTypes () {
final Set <String> result = Sets.newLinkedHashSet ();
for (final Class <?> annotationClass : __annotations__) {
result.add (annotationClass.getName ());
......@@ -141,8 +157,14 @@ public final class DislClassFinder implements Processor {
for (final TypeElement te : annotations) {
for (final Element e : env.getElementsAnnotatedWith (te)) {
final String className = __getEnlosingClassName (e);
if (__dislClasses.add (className)) {
final String className = __getEnclosingClassName (e);
if (className == null) {
__messager.printMessage (Kind.WARNING, String.format (
"could not get enclosing class name for %s (%s)",
e, e.getKind ()
));
} else if (__dislClasses.add (className)) {
newClasses.add (className);
}
}
......@@ -156,8 +178,8 @@ public final class DislClassFinder implements Processor {
}
//
// Force a new line in the output file at the end of processing
// and close the output unless it is system output.
// At the end of processing, force a new line in the output file
// (if required) and close the output (unless it is system output).
//
if (env.processingOver ()) {
if (__forceEol && __dislClasses.size () > 0) {
......@@ -174,21 +196,82 @@ public final class DislClassFinder implements Processor {
}
private String __getEnlosingClassName (final Element initial) {
private String __getEnclosingClassName (final Element element) {
//
// Our annotations apply to classes, methods, and fields.
// For methods and fields, traverse the chain of enclosing
// elements to the top-level class.
// For methods and fields, find the enclosing class and then
// return the binary qualified name of the resulting class.
// Return null if the enclosing class could not be found.
//
final ElementKind kind = element.getKind ();
if (kind.isClass ()) {
return __getBinaryClassName (element);
} else if (kind == ElementKind.METHOD || kind == ElementKind.FIELD) {
final Element parent = element.getEnclosingElement ();
if (parent.getKind ().isClass ()) {
return __getBinaryClassName (parent);
}
}
//
// Could not find enclosing class.
//
return null;
}
private String __getBinaryClassName (final Element element) {
//
// If the parent element is package, we can just use the class name.
// Otherwise we have to traverse the enclosing classes to build the
// binary name.
//
if (element.getEnclosingElement ().getKind () == ElementKind.PACKAGE) {
return element.toString ();
} else {
return __buildBinaryClassName (element);
}
}
private String __buildBinaryClassName (final Element element) {
//
// Replace '.' before inner class names with '$'.
// For details on class binary names, see
//
Element current = initial;
while (true) {
// http://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html#jls-13.1
//
final StringBuilder name = new StringBuilder (element.toString ());
Element current = element;
int lastPosition = name.length ();
TRAVERSAL: while (true) {
final Element parent = current.getEnclosingElement ();
if (parent == null || parent.getKind () == ElementKind.PACKAGE) {
return current.toString ();
if (!parent.getKind ().isClass ()) {
break TRAVERSAL;
}
lastPosition = __lastIndexOf (name, '.', lastPosition);
name.setCharAt (lastPosition, '$');
current = parent;
}
return name.toString ();
}
private int __lastIndexOf (
final StringBuilder sb, final char chr, final int startPosition
) {
int position = Math.min (startPosition, sb.length () - 1);
while (position >= 0 && sb.charAt (position) != chr) {
position--;
}
return position;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment