All Downloads are FREE. Search and download functionalities are using the official Maven repository.

framework.src.org.checkerframework.framework.stub.StubUtil Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 3.42.0
Show newest version
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);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy