package com.sun.tools.javac.comp;
import java.io.PrintWriter;
import java.util.HashSet;
import com.sun.tools.javac.parser.Parser;
import com.sun.tools.javac.tree.TreeScanner;
import com.sun.tools.javac.tree.JCTree.DPJEffect;
import com.sun.tools.javac.tree.JCTree.DPJParamInfo;
import com.sun.tools.javac.tree.JCTree.DPJRegionDecl;
import com.sun.tools.javac.tree.JCTree.DPJRegionParameter;
import com.sun.tools.javac.tree.JCTree.DPJRegionPathList;
import com.sun.tools.javac.tree.JCTree.JCArrayTypeTree;
import com.sun.tools.javac.tree.JCTree.JCClassDecl;
import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCInstanceOf;
import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCNewClass;
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
import com.sun.tools.javac.tree.JCTree.JCTypeCast;
import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
import com.sun.tools.javac.util.Pair;
import com.sun.tools.javac.util.Position;
/** A class for counting DPJ annotations in the code
*
* @author Rob Bocchino
*/
public class DPJAnnotationCounter extends TreeScanner {
public enum Context { CLASS, METHOD_DEF, METHOD_INVOKE, IN, TYPE, READ_EFFECT, WRITE_EFFECT };
public boolean badLineMap = false;
// Basic Java elements
public int classDefCount;
public int methodDefCount;
public int methodInvokeCount;
public int newClassCount;
public int variableDefCount;
public int classTypeParamCount;
public int methodTypeParamCount;
public int baseClassCount;
public int typeTypeArgCount;
public int methodTypeArgCount;
public int instanceofCount;
public int castCount;
// DPJ Annotations
public int annotatedLinesCount;
public int fieldRegionDeclCount;
public int atomicFieldRegionDeclCount;
public int localRegionDeclCount;
public int atomicLocalRegionDeclCount;
public int classRegionParamCount;
public int atomicClassRegionParamCount;
public int typeRegionParamCount;
public int classEffectParamCount;
public int classRPLConstraintCount;
public int classEffectConstraintCount;
public int methodRegionParamCount;
public int atomicMethodRegionParamCount;
public int methodEffectParamCount;
public int methodRPLConstraintCount;
public int methodEffectConstraintCount;
public int inRPLArgCount;
public int typeRPLArgCount;
public int typeEffectArgCount;
public int methodRPLArgCount;
public int methodEffectArgCount;
public int methodEffectSummaryCount;
public int readEffectCount;
public int readEffectRPLCount;
public int atomicReadEffectRPLCount;
public int writeEffectCount;
public int writeEffectRPLCount;
public int atomicWriteEffectRPLCount;
public void printStatistics(PrintWriter out) {
if (badLineMap) {
System.err.println("WARNING: Linemap unavailable for some classes, SLOC count may be inaccurate");
}
System.out.println("*** Basic Java Elements ***");
System.out.println("Class definitions: " + classDefCount);
// Use the parser to count methods, because the compiler later adds
// default constructors that weren't in the source file
System.out.println("Method definitions: " + Parser.methodCount);
System.out.println("Methods invoked: " + methodInvokeCount);
System.out.println("New expressions: " + newClassCount);
System.out.println("Variable definitions: " + variableDefCount);
System.out.println("Class type parameters: " + classTypeParamCount);
System.out.println("Method type parameters: " + methodTypeParamCount);
System.out.println("Base class types: " + baseClassCount);
System.out.println("Type arguments to types: " + typeTypeArgCount);
System.out.println("Type arguments to methods: " + methodTypeArgCount);
System.out.println("Type casts: " + castCount);
System.out.println("Instanceof expressions: " + instanceofCount);
System.out.println("*** DPJ Annotations ***");
System.out.println("Annotated SLOC: "+ annotatedLinesCount);
System.out.println("Total field region declarations: " + fieldRegionDeclCount);
System.out.println("Atomic field region declarations: " + atomicFieldRegionDeclCount);
System.out.println("Total local region declarations: " + localRegionDeclCount);
System.out.println("Atomic local region declarations: " + atomicLocalRegionDeclCount);
System.out.println("Total class region parameters: " + classRegionParamCount);
System.out.println("Atomic class region parameters: " + atomicClassRegionParamCount);
System.out.println("Class RPL constraints: " + classRPLConstraintCount);
System.out.println("Type region parameters: " + typeRegionParamCount);
System.out.println("Class effect parameters: " + classEffectParamCount);
System.out.println("Class effect constraints: " + classEffectConstraintCount);
System.out.println("Total method region parameters: " + methodRegionParamCount);
System.out.println("Atomic method region parameters: " + atomicMethodRegionParamCount);
System.out.println("Method RPL constraints: " + methodRPLConstraintCount);
System.out.println("Method effect parameters: " + methodEffectParamCount);
System.out.println("Method effect constraints: " + methodEffectConstraintCount);
System.out.println("Effect arguments to types: " + typeEffectArgCount);
System.out.println("Effect arguments to methods: " + methodEffectArgCount);
System.out.println("Method effect summaries: " + methodEffectSummaryCount);
System.out.println("Total RPLs in read effects: " + readEffectRPLCount);
System.out.println("Atomic RPLs in read effects: " + atomicReadEffectRPLCount);
System.out.println("Total RPLs in write effects: " + writeEffectRPLCount);
System.out.println("Atomic RPLs in write effects: " + atomicWriteEffectRPLCount);
System.out.println("RPL arguments to 'in': " + inRPLArgCount);
System.out.println("RPL arguments to types: " + typeRPLArgCount);
System.out.println("RPL arguments to methods: " + methodRPLArgCount);
}
/** Visitor argument: The current context
*/
public Context context;
/** Visitor argument: Set for tracking annotated lines
*/
HashSet<Integer> annotatedLines = null;
/** Visitor argument: Map from positions to line numbers
*/
Position.LineMap lineMap = null;
/** Add the line for the given pos to the set of annotated lines
* for the current class. javac does something funny with lineMaps,
* so we add some code to check whether a lineMap wasn't available.
* @param pos
*/
void addLineFor(int pos) {
if (lineMap == null) {
badLineMap = true;
return;
}
annotatedLines.add(lineMap.getLineNumber(pos));
}
@Override
public void visitTopLevel(JCCompilationUnit tree) {
lineMap = tree.getLineMap();
super.visitTopLevel(tree);
}
HashSet<JCClassDecl> visited = new HashSet<JCClassDecl>();
@Override
public void visitClassDef(JCClassDecl tree) {
// TODO: Why do some classes get visited twice???
if (!visited.add(tree)) return;
++classDefCount;
if (tree.extending != null)
++baseClassCount;
if (tree.implementing != null)
baseClassCount += tree.implementing.size();
Context savedContext = context;
context = Context.CLASS;
HashSet<Integer> savedAnnotatedLines = annotatedLines;
annotatedLines = new HashSet<Integer>();
super.visitClassDef(tree);
annotatedLinesCount += annotatedLines.size();
context = savedContext;
annotatedLines = savedAnnotatedLines;
}
@Override
public void visitTypeParameter(JCTypeParameter tree) {
int rplParamsCount = tree.rplparams.size();
if (rplParamsCount != 0) {
addLineFor(tree.pos);
typeRegionParamCount += rplParamsCount;
}
switch (context) {
case CLASS:
++classTypeParamCount;
break;
case METHOD_DEF:
++methodTypeParamCount;
break;
default:
assert false;
}
}
@Override
public void visitMethodDef(JCMethodDecl tree) {
++methodDefCount;
Context savedContext = context;
context = Context.METHOD_DEF;
super.visitMethodDef(tree);
context = savedContext;
}
@Override
public void visitApply(JCMethodInvocation tree) {
++methodInvokeCount;
methodTypeArgCount += tree.typeargs.size();
scan(tree.meth);
Context savedContext = context;
context = Context.METHOD_INVOKE;
scan(tree.regionArgs);
scan(tree.effectargs);
context = savedContext;
scan(tree.typeargs);
scan(tree.args);
}
@Override
public void visitParamInfo(DPJParamInfo tree) {
scan(tree.rplParams);
for (Pair<DPJRegionPathList,DPJRegionPathList> pair : tree.rplConstraints) {
addLineFor(pair.fst.pos);
addLineFor(pair.snd.pos);
}
for (JCIdent effectParam : tree.effectParams) {
addLineFor(effectParam.pos);
switch (context) {
case CLASS:
++classEffectParamCount;
break;
case METHOD_DEF:
++methodEffectParamCount;
break;
default:
assert false;
}
}
for (Pair<DPJEffect,DPJEffect> pair : tree.effectConstraints) {
addLineFor(pair.fst.pos);
addLineFor(pair.snd.pos);
}
switch (context) {
case CLASS:
classRPLConstraintCount += tree.rplConstraints.size();
classEffectConstraintCount += tree.effectConstraints.size();
break;
case METHOD_DEF:
methodRPLConstraintCount += tree.rplConstraints.size();
methodEffectConstraintCount += tree.effectConstraints.size();
break;
default:
assert false;
}
}
@Override
public void visitRegionParameter(DPJRegionParameter tree) {
addLineFor(tree.pos);
switch (context) {
case CLASS:
++classRegionParamCount;
if (tree.isAtomic)
++atomicClassRegionParamCount;
break;
case METHOD_DEF:
++methodRegionParamCount;
if (tree.isAtomic)
++atomicMethodRegionParamCount;
break;
default:
assert false;
}
}
@Override
public void visitVarDef(JCVariableDecl tree) {
++variableDefCount;
Context savedContext = context;
context = Context.IN;
super.visitVarDef(tree);
context = savedContext;
}
@Override
public void visitRPL(DPJRegionPathList tree) {
addLineFor(tree.pos);
switch (context) {
case IN:
++inRPLArgCount;
break;
case TYPE:
++typeRPLArgCount;
break;
case METHOD_INVOKE:
++methodRPLArgCount;
break;
case READ_EFFECT:
++readEffectRPLCount;
if (tree.isAtomic)
++atomicReadEffectRPLCount;
break;
case WRITE_EFFECT:
++writeEffectRPLCount;
if (tree.isAtomic)
++atomicWriteEffectRPLCount;
break;
default:
assert false;
}
}
@Override
public void visitRegionDecl(DPJRegionDecl tree) {
addLineFor(tree.pos);
switch (context) {
case CLASS:
++fieldRegionDeclCount;
if (tree.isAtomic)
++atomicFieldRegionDeclCount;
break;
case METHOD_DEF:
++localRegionDeclCount;
if (tree.isAtomic)
++atomicLocalRegionDeclCount;
break;
default:
assert false;
}
}
@Override
public void visitTypeApply(JCTypeApply tree) {
typeTypeArgCount += tree.typeArgs.size();
Context savedContext = context;
context = Context.TYPE;
super.visitTypeApply(tree);
context = savedContext;
}
@Override
public void visitTypeArray(JCArrayTypeTree tree) {
Context savedContext = context;
context = Context.TYPE;
super.visitTypeArray(tree);
context = savedContext;
}
@Override
public void visitEffect(DPJEffect tree) {
if (tree.isPure || tree.readEffects.nonEmpty() ||
tree.writeEffects.nonEmpty())
addLineFor(tree.pos);
else
return;
switch (context) {
case TYPE:
++typeEffectArgCount;
break;
case METHOD_INVOKE:
++methodEffectArgCount;
break;
case METHOD_DEF:
++methodEffectSummaryCount;
break;
default:
assert false;
}
Context savedContext = context;
if (tree.readEffects != null && tree.readEffects.size() > 0) {
++readEffectCount;
context = Context.READ_EFFECT;
scan(tree.readEffects);
}
if (tree.writeEffects != null && tree.writeEffects.size() > 0) {
++writeEffectCount;
context = Context.WRITE_EFFECT;
scan(tree.writeEffects);
}
context = savedContext;
}
public void visitTypeCast(JCTypeCast tree) {
++castCount;
super.visitTypeCast(tree);
}
public void visitTypeTest(JCInstanceOf tree) {
++instanceofCount;
super.visitTypeTest(tree);
}
public void visitNewClass(JCNewClass tree) {
++newClassCount;
super.visitNewClass(tree);
}
}