com.microsoft.javapkgsrv.JavaParser.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.javapkgsrv.JavaParser.java

Source

// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT License.  See LICENSE file in the project root for license information.

package com.microsoft.javapkgsrv;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModel;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.SourceRange;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jface.text.Document;

import com.microsoft.javapkgsrv.Protocol.TypeRootIdentifier;
import com.microsoft.javapkgsrv.Protocol.Response.FileParseMessagesResponse.Problem;
import com.microsoft.javapkgsrv.Protocol.Response.QuickInfoResponse.JavaElement;
import com.microsoft.javapkgsrv.Protocol.Response.*;

public class JavaParser {
    private HashMap<Integer, CompilationUnit> ActiveUnits = new HashMap<Integer, CompilationUnit>();
    private HashMap<String, ITypeRoot> ActiveTypeRoots = new HashMap<String, ITypeRoot>();
    public IWorkspaceRoot WorkspaceRoot = null;
    public IJavaModel JavaModel = null;

    public void Init() throws JavaModelException {
        WorkspaceRoot = ResourcesPlugin.getWorkspace().getRoot();

        JavaModel = JavaCore.create(WorkspaceRoot);
        System.out.println("Updating external archives...");
        JavaModel.refreshExternalArchives(null, null);
    }

    public Integer ProcessParseRequest(String contentFile, String fileName) throws Exception {
        CompilationUnit cu = Parse(contentFile, fileName);
        int hashCode = cu.hashCode();
        ActiveUnits.put(hashCode, cu);
        return hashCode;
    }

    public void ProcessDisposeFileRequest(int fileIdentifier) {
        if (ActiveUnits.containsKey(fileIdentifier))
            ActiveUnits.remove(fileIdentifier);
    }

    private CompilationUnit Parse(String contentFile, String fileName) throws Exception {
        File file = new File(fileName);
        IFile[] files = WorkspaceRoot.findFilesForLocationURI(file.toURI(), IResource.FILE);

        if (files.length > 1)
            throw new Exception("Ambigous parse request for file: " + fileName);
        else if (files.length == 0)
            throw new Exception("File is not part of the enlistment: " + fileName);

        ASTParser parser = ASTParser.newParser(AST.JLS8);
        parser.setKind(ASTParser.K_COMPILATION_UNIT);
        parser.setSource(contentFile.toCharArray());
        parser.setUnitName(files[0].getName());
        parser.setProject(JavaCore.create(files[0].getProject()));
        parser.setResolveBindings(true);

        CompilationUnit cu = (CompilationUnit) parser.createAST(null);
        return cu;
    }

    public List<Protocol.Response.OutlineResultResponse.Outline> ProcessOutlineRequest(Integer fileId) {
        final List<OutlineResultResponse.Outline> ret = new ArrayList<OutlineResultResponse.Outline>();
        if (ActiveUnits.containsKey(fileId)) {
            CompilationUnit cu = ActiveUnits.get(fileId);
            cu.accept(new ASTVisitor() {
                @Override
                public boolean visit(TypeDeclaration type) {
                    ret.add(OutlineResultResponse.Outline.newBuilder().setStartPosition(type.getStartPosition())
                            .setLength(type.getLength()).setHoverText(type.toString())
                            .setSummaryText(type.getName().toString()).build());
                    return true;
                }

                @Override
                public boolean visit(MethodDeclaration method) {
                    ret.add(OutlineResultResponse.Outline.newBuilder().setStartPosition(method.getStartPosition())
                            .setLength(method.getLength()).setHoverText(method.toString())
                            .setSummaryText(method.getName().toString()).build());
                    return true;
                }
            });
        }
        return ret;
    }

    public List<AutocompleteResponse.Completion> ProcessAutocompleteRequest(String contentFile, String typeRootId,
            int cursorPosition) throws Exception {
        if (ActiveTypeRoots.containsKey(typeRootId)) {
            ITypeRoot typeRoot = ActiveTypeRoots.get(typeRootId);
            typeRoot.getBuffer().setContents(contentFile.toCharArray());
            return Autocomplete(typeRoot, cursorPosition);
        }
        return null;
    }

    private List<AutocompleteResponse.Completion> Autocomplete(ITypeRoot cu, int cursorPosition)
            throws JavaModelException {
        final List<AutocompleteResponse.Completion> proposals = new ArrayList<AutocompleteResponse.Completion>();
        cu.codeComplete(cursorPosition, new CompletionRequestor() {
            @Override
            public void accept(CompletionProposal proposal) {
                try {
                    System.out.println(proposal.toString());
                    proposals.add(translateToCompletion(proposal));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        return proposals;
    }

    private AutocompleteResponse.Completion translateToCompletion(CompletionProposal proposal) {
        AutocompleteResponse.Completion.Builder builder = AutocompleteResponse.Completion.newBuilder()
                .setKind(AutocompleteResponse.Completion.CompletionKind.valueOf(proposal.getKind()))
                .setIsConstructor(proposal.isConstructor())
                .setCompletionText(String.copyValueOf(proposal.getCompletion())).setFlags(proposal.getFlags())
                .setRelevance(proposal.getRelevance()).setReplaceStart(proposal.getReplaceStart())
                .setReplaceEnd(proposal.getReplaceEnd());

        char[] sig = proposal.getSignature();

        if (sig != null) {
            if (proposal.getKind() == CompletionProposal.METHOD_REF
                    || proposal.getKind() == CompletionProposal.JAVADOC_METHOD_REF)
                builder.setSignature(new String(Signature.toCharArray(sig, proposal.getName(), null, false, true)));
            else
                builder.setSignature(new String(Signature.toCharArray(sig)));
        }
        char[] name = proposal.getName();
        if (name == null)
            builder.setName(builder.getCompletionText());
        else
            builder.setName(String.copyValueOf(name));
        return builder.build();
    }

    public List<ParamHelpResponse.Signature> ProcessParamHelpRequest(String contentFile, String typeRootId,
            int cursorPosition) throws Exception {
        if (ActiveTypeRoots.containsKey(typeRootId)) {
            ITypeRoot typeRoot = ActiveTypeRoots.get(typeRootId);
            typeRoot.getBuffer().setContents(contentFile.toCharArray());
            return ParamHelp(typeRoot, cursorPosition);
        }
        return null;
    }

    private List<ParamHelpResponse.Signature> ParamHelp(ITypeRoot cu, int cursorPosition)
            throws JavaModelException {
        final List<ParamHelpResponse.Signature> proposals = new ArrayList<ParamHelpResponse.Signature>();
        cu.codeComplete(cursorPosition, new CompletionRequestor() {
            @Override
            public void accept(CompletionProposal proposal) {
                try {
                    System.out.println(proposal.toString());
                    if (proposal.getKind() == CompletionProposal.METHOD_REF) {
                        char[] javaSig = proposal.getSignature();

                        ParamHelpResponse.Signature.Builder sig = ParamHelpResponse.Signature.newBuilder()
                                .setName(new String(proposal.getName())).setReturnValue(
                                        new String(Signature.toCharArray(Signature.getReturnType(javaSig))));

                        char[][] javaParamTypes = Signature.getParameterTypes(javaSig);
                        for (char[] javaParamType : javaParamTypes) {
                            sig.addParameters(ParamHelpResponse.Parameter.newBuilder()
                                    .setName(new String(Signature.toCharArray(javaParamType))).build());
                        }
                        proposals.add(sig.build());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
        return proposals;
    }

    protected final static char[] BRACKETS = { '{', '}', '(', ')', '[', ']', '<', '>' };
    protected final static char[] SEPARATORS = { ',' };

    public JavaParamHelpMatcher.ParamRegion getScope(String fileParseContent, int cursorPosition) {
        JavaParamHelpMatcher matcher = new JavaParamHelpMatcher(BRACKETS, SEPARATORS);
        Document doc = new Document(fileParseContent);

        return matcher.findEnclosingPeerCharacters(doc, cursorPosition, 0);
    }

    public JavaParamHelpMatcher.ParamRegion updateScope(String fileParseContents, int cursorPosition) {
        JavaParamHelpMatcher matcher = new JavaParamHelpMatcher(BRACKETS, SEPARATORS);
        Document doc = new Document(fileParseContents);

        return matcher.findEnclosingPeerCharacters(doc, cursorPosition, 0);
    }

    public List<Problem> ProcessFileParseMessagesRequest(Integer fileId) {
        List<FileParseMessagesResponse.Problem> ret = new ArrayList<FileParseMessagesResponse.Problem>();
        if (ActiveUnits.containsKey(fileId)) {
            CompilationUnit cu = ActiveUnits.get(fileId);
            IProblem[] problems = cu.getProblems();

            for (IProblem problem : problems) {
                System.out.println(problem.toString());
                FileParseMessagesResponse.Problem.Builder retProblem = FileParseMessagesResponse.Problem
                        .newBuilder().setId(problem.getID()).setMessage(problem.getMessage())
                        .setFileName(new String(problem.getOriginatingFileName()))
                        .setScopeStart(problem.getSourceStart()).setScopeEnd(problem.getSourceEnd() + 1)
                        .setLineNumber(problem.getSourceLineNumber()).setProblemType(GetProblemType(problem));
                for (String arg : problem.getArguments())
                    retProblem.addArguments(arg);
                ret.add(retProblem.build());
            }
        }
        return ret;
    }

    private FileParseMessagesResponse.Problem.ProblemType GetProblemType(IProblem problem) {
        if (problem.isError())
            return FileParseMessagesResponse.Problem.ProblemType.Error;
        if (problem.isWarning())
            return FileParseMessagesResponse.Problem.ProblemType.Warning;
        return FileParseMessagesResponse.Problem.ProblemType.Message;
    }

    public List<JavaElement> ProcessQuickInfoRequest(String fileParseContents, String typeRootId,
            int cursorPosition) throws Exception {
        if (ActiveTypeRoots.containsKey(typeRootId)) {
            ITypeRoot cu = ActiveTypeRoots.get(typeRootId);
            cu.getBuffer().setContents(fileParseContents.toCharArray());
            IJavaElement[] elements = cu.codeSelect(cursorPosition, 0);

            List<JavaElement> ret = new ArrayList<JavaElement>();

            long flags = JavaElementLabelComposer.ALL_FULLY_QUALIFIED | JavaElementLabelComposer.ALL_DEFAULT
                    | JavaElementLabelComposer.M_PRE_RETURNTYPE | JavaElementLabelComposer.F_PRE_TYPE_SIGNATURE;
            for (IJavaElement element : elements) {
                StringBuffer buffer = new StringBuffer();
                JavaElementLabelComposer composer = new JavaElementLabelComposer(buffer);

                composer.appendElementLabel(element, flags);
                System.out.println(element.getPath().toString());

                JavaElement.Builder b = JavaElement.newBuilder().setDefinition(buffer.toString());

                String javaDoc = null;
                try {
                    javaDoc = element.getAttachedJavadoc(null);
                } catch (JavaModelException jme) {
                    jme.printStackTrace();
                }
                if (javaDoc != null)
                    b.setJavaDoc(javaDoc);
                ret.add(b.build());
            }
            return ret;
        }
        return null;
    }

    public List<FindDefinitionResponse.JavaElement> ProcessFindDefinintionRequest(String fileParseContents,
            String typeRootId, int cursorPosition) throws Exception {
        if (ActiveTypeRoots.containsKey(typeRootId)) {
            ITypeRoot cu = ActiveTypeRoots.get(typeRootId);
            cu.getBuffer().setContents(fileParseContents.toCharArray());
            IJavaElement[] elements = cu.codeSelect(cursorPosition, 0);

            List<FindDefinitionResponse.JavaElement> ret = new ArrayList<FindDefinitionResponse.JavaElement>();
            for (IJavaElement element : elements) {
                String definition = element.toString();
                String path = element.getResource() != null ? element.getResource().getLocation().toOSString()
                        : element.getPath().toOSString();
                //String path = element.getPath().makeAbsolute().toOSString(); // element.getPath().toString();

                boolean isAvailable = false;
                int posStart = -1;
                int posLength = 0;
                String contents = null;
                String classFileName = null;
                IClassFile classFileObj = null;

                ISourceReference srcRef = (ISourceReference) element;
                if (srcRef != null) {
                    ISourceRange range = srcRef.getSourceRange();
                    if (SourceRange.isAvailable(range)) {
                        isAvailable = true;
                        posStart = range.getOffset();
                        posLength = range.getLength();

                        //if (path.endsWith(".jar"))
                        //{
                        IOpenable op = element.getOpenable();
                        if (op != null && op instanceof IClassFile) {
                            IBuffer buff = op.getBuffer();
                            classFileObj = (IClassFile) op;
                            classFileName = classFileObj.getElementName();
                            contents = buff.getContents();
                        }
                        //}
                    }
                }

                FindDefinitionResponse.JavaElement.Builder retItem = FindDefinitionResponse.JavaElement.newBuilder()
                        .setDefinition(definition).setFilePath(path).setHasSource(isAvailable)
                        .setPositionStart(posStart).setPositionLength(posLength);

                if (contents != null) {
                    //int hashCode = classFileObj.hashCode();
                    String handle = classFileObj.getHandleIdentifier();
                    ActiveTypeRoots.put(handle, classFileObj);

                    retItem.setFileName(classFileName);
                    retItem.setTypeRootIdentifier(TypeRootIdentifier.newBuilder().setHandle(handle).build());
                }
                System.out.println(retItem.toString());
                if (contents != null) {
                    retItem.setFileContents(contents);
                }
                ret.add(retItem.build());
            }
            return ret;
        }
        return null;
    }

    public String ProcessOpenTypeRequest(String fileName) throws Exception {
        File file = new File(fileName);
        IFile[] files = WorkspaceRoot.findFilesForLocationURI(file.toURI(), IResource.FILE);

        if (files.length > 1)
            throw new Exception("Ambigous parse request for file " + fileName);
        else if (files.length == 0)
            throw new Exception("File not found: " + fileName);

        IJavaElement javaFile = JavaCore.create(files[0]);
        if (javaFile instanceof ITypeRoot) {
            //int hashCode = javaFile.hashCode();
            String handle = javaFile.getHandleIdentifier();
            ActiveTypeRoots.put(handle, (ITypeRoot) javaFile);
            return handle;
        }
        return null;
    }

    public void ProcessDisposeTypeRoot(String handle) {
        if (ActiveTypeRoots.containsKey(handle))
            ActiveTypeRoots.remove(handle);
    }

    public String ProcessAddTypeRequest(String handle) {
        IJavaElement javaFile = JavaCore.create(handle);
        if (javaFile instanceof ITypeRoot) {
            String newHandle = javaFile.getHandleIdentifier();
            ActiveTypeRoots.put(newHandle, (ITypeRoot) javaFile);
            return newHandle;
        }
        return null;
    }
}