framework.src.org.checkerframework.framework.stub.StubUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of checker Show documentation
Show all versions of checker Show documentation
The Checker Framework enhances Java’s type system to
make it more powerful and useful. This lets software developers
detect and prevent errors in their Java programs.
The Checker Framework includes compiler plug-ins ("checkers")
that find bugs or verify their absence. It also permits you to
write your own compiler plug-ins.
package org.checkerframework.framework.stub;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.type.TypeVariable;
import org.checkerframework.javacutil.ErrorReporter;
import org.checkerframework.javacutil.Pair;
import org.checkerframework.stubparser.ast.CompilationUnit;
import org.checkerframework.stubparser.ast.IndexUnit;
import org.checkerframework.stubparser.ast.Node;
import org.checkerframework.stubparser.ast.body.BodyDeclaration;
import org.checkerframework.stubparser.ast.body.ConstructorDeclaration;
import org.checkerframework.stubparser.ast.body.FieldDeclaration;
import org.checkerframework.stubparser.ast.body.MethodDeclaration;
import org.checkerframework.stubparser.ast.body.Parameter;
import org.checkerframework.stubparser.ast.body.TypeDeclaration;
import org.checkerframework.stubparser.ast.body.VariableDeclarator;
import org.checkerframework.stubparser.ast.type.ClassOrInterfaceType;
import org.checkerframework.stubparser.ast.type.PrimitiveType;
import org.checkerframework.stubparser.ast.type.ReferenceType;
import org.checkerframework.stubparser.ast.type.VoidType;
import org.checkerframework.stubparser.ast.type.WildcardType;
import org.checkerframework.stubparser.ast.visitor.SimpleVoidVisitor;
/**
* Utility class for stub files
*/
public class StubUtil {
/*package-scope*/ static TypeDeclaration findDeclaration(String className, IndexUnit indexFile) {
int indexOfDot = className.lastIndexOf('.');
if (indexOfDot == -1) {
// classes not within a package needs to be the first in the index file
assert !indexFile.getCompilationUnits().isEmpty();
assert indexFile.getCompilationUnits().get(0).getPackage() == null;
return findDeclaration(className, indexFile.getCompilationUnits().get(0));
}
final String packageName = className.substring(0, indexOfDot);
final String simpleName = className.substring(indexOfDot + 1);
for (CompilationUnit cu : indexFile.getCompilationUnits()) {
if (cu.getPackage() != null && cu.getPackage().getName().getName().equals(packageName)) {
TypeDeclaration type = findDeclaration(simpleName, cu);
if (type != null) {
return type;
}
}
}
// Couldn't find it
return null;
}
/*package-scope*/ static TypeDeclaration findDeclaration(TypeElement type, IndexUnit indexFile) {
return findDeclaration(type.getQualifiedName().toString(), indexFile);
}
/*package-scope*/ static FieldDeclaration findDeclaration(VariableElement field, IndexUnit indexFile) {
TypeDeclaration type = findDeclaration((TypeElement)field.getEnclosingElement(), indexFile);
if (type == null) {
return null;
}
for (BodyDeclaration member : type.getMembers()) {
if (!(member instanceof FieldDeclaration)) {
continue;
}
FieldDeclaration decl = (FieldDeclaration)member;
for (VariableDeclarator var : decl.getVariables()) {
if (toString(var).equals(field.getSimpleName().toString())) {
return decl;
}
}
}
return null;
}
/*package-scope*/ static BodyDeclaration findDeclaration(ExecutableElement method, IndexUnit indexFile) {
TypeDeclaration type = findDeclaration((TypeElement)method.getEnclosingElement(), indexFile);
if (type == null) {
return null;
}
String methodRep = toString(method);
for (BodyDeclaration member : type.getMembers()) {
if (member instanceof MethodDeclaration) {
if (toString((MethodDeclaration)member).equals(methodRep)) {
return member;
}
} else if (member instanceof ConstructorDeclaration) {
if (toString((ConstructorDeclaration)member).equals(methodRep)) {
return member;
}
}
}
return null;
}
/*package-scope*/ static TypeDeclaration findDeclaration(String simpleName, CompilationUnit cu) {
for (TypeDeclaration type : cu.getTypes()) {
if (simpleName.equals(type.getName())) {
return type;
}
}
// Couldn't find it
return null;
}
/*package-scope*/ static String toString(MethodDeclaration method) {
return ElementPrinter.toString(method);
}
/*package-scope*/ static String toString(ConstructorDeclaration constructor) {
return ElementPrinter.toString(constructor);
}
/*package-scope*/ static String toString(VariableDeclarator field) {
return field.getId().getName();
}
/*package-scope*/ static String toString(FieldDeclaration field) {
assert field.getVariables().size() == 1;
return toString(field.getVariables().get(0));
}
/**
* Returns the chosen canonical string of the method declaration.
*
* The canonical representation contains simple names of the types only.
*/
/*package-scope*/ static String toString(ExecutableElement element) {
StringBuilder sb = new StringBuilder();
// note: constructor simple name is
sb.append(element.getSimpleName());
sb.append("(");
for (Iterator i = element.getParameters().iterator(); i.hasNext();) {
sb.append(standarizeType(i.next().asType()));
if (i.hasNext()) {
sb.append(",");
}
}
sb.append(")");
return sb.toString();
}
/*package-scope*/ static String toString(VariableElement element) {
assert element.getKind().isField();
return element.getSimpleName().toString();
}
/*package-scope*/ static String toString(Element element) {
if (element instanceof ExecutableElement) {
return toString((ExecutableElement)element);
} else if (element instanceof VariableElement) {
return toString((VariableElement)element);
} else {
return null;
}
}
/*package-scope*/ static Pair partitionQualifiedName(String imported) {
String typeName = imported.substring(0, imported.lastIndexOf("."));
String name = imported.substring(imported.lastIndexOf(".") + 1);
Pair typeParts = Pair.of(typeName, name);
return typeParts;
}
/**
* A helper method that standarize type by printing simple names
* instead of fully qualified names.
*
* This eliminates the need for imports.
*/
private static String standarizeType(TypeMirror type) {
switch (type.getKind()) {
case ARRAY:
return standarizeType(((ArrayType)type).getComponentType()) + "[]";
case TYPEVAR:
return ((TypeVariable)type).asElement().getSimpleName().toString();
case DECLARED: {
return ((DeclaredType)type).asElement().getSimpleName().toString();
}
default:
if (type.getKind().isPrimitive()) {
return type.toString();
}
}
ErrorReporter.errorAbort("StubUtil: unhandled type: " + type);
return null; // dead code
}
private final static class ElementPrinter extends SimpleVoidVisitor {
public static String toString(Node n) {
ElementPrinter printer = new ElementPrinter();
n.accept(printer, null);
return printer.getOutput();
}
private final StringBuilder sb = new StringBuilder();
public String getOutput() {
return sb.toString();
}
@Override
public void visit(ConstructorDeclaration n, Void arg) {
sb.append("");
sb.append("(");
if (n.getParameters() != null) {
for (Iterator i = n.getParameters().iterator(); i.hasNext();) {
Parameter p = i.next();
p.accept(this, arg);
if (i.hasNext()) {
sb.append(",");
}
}
}
sb.append(")");
}
@Override
public void visit(MethodDeclaration n, Void arg) {
sb.append(n.getName());
sb.append("(");
if (n.getParameters() != null) {
for (Iterator i = n.getParameters().iterator(); i.hasNext();) {
Parameter p = i.next();
p.accept(this, arg);
if (i.hasNext()) {
sb.append(",");
}
}
}
sb.append(")");
}
@Override
public void visit(Parameter n, Void arg) {
if (n.getId().getArrayCount() > 0) {
ErrorReporter.errorAbort("StubUtil: put array brackets on the type, not the variable: " + n);
}
n.getType().accept(this, arg);
if (n.isVarArgs()) {
sb.append("[]");
}
}
// Types
@Override
public void visit(ClassOrInterfaceType n, Void arg) {
sb.append(n.getName());
}
@Override
public void visit(PrimitiveType n, Void arg) {
switch (n.getType()) {
case Boolean:
sb.append("boolean");
break;
case Byte:
sb.append("byte");
break;
case Char:
sb.append("char");
break;
case Double:
sb.append("double");
break;
case Float:
sb.append("float");
break;
case Int:
sb.append("int");
break;
case Long:
sb.append("long");
break;
case Short:
sb.append("short");
break;
default:
ErrorReporter.errorAbort("StubUtil: unknown type: " + n.getType());
}
}
@Override
public void visit(ReferenceType n, Void arg) {
n.getType().accept(this, arg);
for (int i = 0; i < n.getArrayCount(); ++i) {
sb.append("[]");
}
}
@Override
public void visit(VoidType n, Void arg) {
sb.append("void");
}
@Override
public void visit(WildcardType n, Void arg) {
// We don't write type arguments
// TODO: Why?
ErrorReporter.errorAbort("StubUtil: don't print type args!");
}
}
public static List allStubFiles(String stub) {
List resources = new ArrayList();
File stubFile = new File(stub);
if (stubFile.exists()) {
allStubFiles(stubFile, resources);
} else {
// If the stubFile doesn't exist, maybe it is relative to the
// current working directory, so try that.
String workingDir = System.getProperty("user.dir")
+ System.getProperty("file.separator");
stubFile = new File(workingDir + stub);
if (stubFile.exists()) {
allStubFiles(stubFile, resources);
}
}
return resources;
}
private static boolean isStub(File f) {
return f.isFile() && isStub(f.getName());
}
private static boolean isStub(String path) {
return path.endsWith(".astub");
}
private static boolean isJar(File f) {
return f.isFile() && f.getName().endsWith(".jar");
}
/**
* Side-effects resources
by adding to it either
* stub
if it is a stub file, or all the contained stub
* files if stub
is a jar file or a directory.
*/
private static void allStubFiles(File stub, List resources) {
if (isStub(stub)) {
resources.add(new FileStubResource(stub));
} else if (isJar(stub)) {
JarFile file;
try {
file = new JarFile(stub);
} catch (IOException e) {
System.err.println("StubUtil: could not process JAR file: " + stub);
return;
}
Enumeration entries = file.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (isStub(entry.getName())) {
resources.add(new JarEntryStubResource(file, entry));
}
}
} else if (stub.isDirectory()) {
File[] directoryContents = stub.listFiles();
Arrays.sort(directoryContents, new Comparator() {
@Override
public int compare(File o1, File o2) {
return o1.getName().compareTo(o2.getName());
}
});
for (File enclosed : directoryContents) {
allStubFiles(enclosed, resources);
}
}
}
}