org.eclipse.recommenders.codesearch.rcp.index.extdoc.LocalExamplesProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.recommenders.codesearch.rcp.index.extdoc.LocalExamplesProvider.java

Source

/**
 * Copyright (c) 2012 Tobias Boehm.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *    Tobias Boehm - initial API and implementation.
 */

package org.eclipse.recommenders.codesearch.rcp.index.extdoc;

import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;
import static org.eclipse.recommenders.codesearch.rcp.index.indexer.BindingHelper.getIdentifier;
import static org.eclipse.recommenders.codesearch.rcp.index.searcher.CodeSearcher.prepareSearchTerm;
import static org.eclipse.recommenders.extdoc.rcp.providers.ExtdocProvider.Status.NOT_AVAILABLE;
import static org.eclipse.recommenders.extdoc.rcp.providers.ExtdocProvider.Status.OK;
import static org.eclipse.recommenders.rcp.events.JavaSelectionEvent.JavaSelectionLocation.METHOD_BODY;

import java.io.IOException;
import java.util.List;

import javax.inject.Inject;

import org.apache.lucene.index.Term;
import org.apache.lucene.search.BooleanClause.Occur;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.TermQuery;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.ILocalVariable;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.internal.corext.dom.LinkedNodeFinder;
import org.eclipse.recommenders.codesearch.rcp.index.Fields;
import org.eclipse.recommenders.codesearch.rcp.index.indexer.BindingHelper;
import org.eclipse.recommenders.codesearch.rcp.index.searcher.CodeSearcher;
import org.eclipse.recommenders.codesearch.rcp.index.searcher.SearchResult;
import org.eclipse.recommenders.extdoc.rcp.providers.ExtdocProvider;
import org.eclipse.recommenders.extdoc.rcp.providers.JavaSelectionSubscriber;
import org.eclipse.recommenders.rcp.events.JavaSelectionEvent;
import org.eclipse.recommenders.utils.Tuple;
import org.eclipse.recommenders.utils.rcp.JavaElementResolver;
import org.eclipse.recommenders.utils.rcp.JdtUtils;
import org.eclipse.swt.widgets.Composite;

import com.google.common.base.Optional;
import com.google.common.base.Stopwatch;
import com.google.common.collect.Lists;

@SuppressWarnings("restriction")
public class LocalExamplesProvider extends ExtdocProvider {

    private final JavaElementResolver jdtResolver;
    private final CodeSearcher searcher;
    private Stopwatch watch;
    private JavaSelectionEvent event;

    private MethodDeclaration enclosingMethod;
    private TypeDeclaration enclosingType;
    private SimpleName varNode;
    private String varType;

    List<String> searchterms;
    private IType jdtVarType;

    @Inject
    public LocalExamplesProvider(final CodeSearcher searcher, final JavaElementResolver jdtResolver)
            throws IOException {
        this.searcher = searcher;
        this.jdtResolver = jdtResolver;
    }

    @JavaSelectionSubscriber(METHOD_BODY)
    public Status onFieldSelection(final IField var, final JavaSelectionEvent event, final Composite parent)
            throws IOException, JavaModelException {
        this.event = event;
        startMeasurement();
        if (!findAstNodes()) {
            return NOT_AVAILABLE;
        }

        if (!findVariableType(var.getTypeSignature())) {
            return NOT_AVAILABLE;
        }

        final BooleanQuery query = createQuery();
        final SearchResult searchResult = searcher.lenientSearch(query, 5000);
        stopMeasurement();

        runSyncInUiThread(new Renderer(searchResult, parent, varType, watch.toString(), jdtResolver, searchterms));
        return OK;
    }

    @JavaSelectionSubscriber
    public Status onVariableSelection(final ILocalVariable var, final JavaSelectionEvent event,
            final Composite parent) throws IOException, JavaModelException {
        this.event = event;
        startMeasurement();
        if (!findAstNodes()) {
            return NOT_AVAILABLE;
        }

        if (!findVariableType(var.getTypeSignature())) {
            return NOT_AVAILABLE;
        }

        final BooleanQuery query = createQuery();
        final SearchResult searchResults = searcher.lenientSearch(query, 5000);
        stopMeasurement();

        runSyncInUiThread(new Renderer(searchResults, parent, varType, watch.toString(), jdtResolver, searchterms));
        return OK;
    }

    private boolean findAstNodes() {
        final Optional<ASTNode> astNode = event.getSelectedNode();
        if (!astNode.isPresent()) {
            return false;
        }
        final ASTNode node = astNode.get();
        if (node.getNodeType() == ASTNode.SIMPLE_NAME) {
            varNode = (SimpleName) node;
        }

        for (ASTNode parent = varNode; parent != null; parent = parent.getParent()) {
            if (parent instanceof MethodDeclaration) {
                enclosingMethod = (MethodDeclaration) parent;
            } else if (parent instanceof TypeDeclaration) {
                enclosingType = (TypeDeclaration) parent;
                break;
            }
        }
        return varNode != null && enclosingMethod != null && enclosingType != null;
    }

    private boolean findVariableType(final String typeSignature) {

        final Optional<IMethod> method = JdtUtils.resolveMethod(enclosingMethod);
        if (!method.isPresent()) {
            return false;
        }

        final Optional<IType> opt = JdtUtils.findTypeFromSignature(typeSignature, method.get());
        if (!opt.isPresent()) {
            return false;
        }
        jdtVarType = opt.get();
        varType = jdtResolver.toRecType(opt.get()).getIdentifier();
        return varType != null;
    }

    private BooleanQuery createQuery() {

        // TODO: cleanup needed

        final BooleanQuery query = new BooleanQuery();
        final Term typeTerm = prepareSearchTerm(Fields.VARIABLE_TYPE, varType);
        final TermQuery typeQuery = new TermQuery(typeTerm);
        query.add(typeQuery, Occur.MUST);
        searchterms = Lists.newArrayList();
        searchterms.add(varNode.getIdentifier());
        searchterms.add(jdtVarType.getElementName());

        for (final SimpleName use : LinkedNodeFinder.findByNode(enclosingMethod, varNode)) {

            final ASTNode astParent = use.getParent();
            Term term = null;
            switch (astParent.getNodeType()) {
            case ASTNode.CLASS_INSTANCE_CREATION: {
                final ClassInstanceCreation targetMethod = (ClassInstanceCreation) astParent;
                final IMethodBinding methodBinding = targetMethod.resolveConstructorBinding();
                final Optional<String> optMethod = BindingHelper.getIdentifier(methodBinding);
                if (!optMethod.isPresent()) {
                    break;
                }
                // matches more than the method itself, but that'S a minor thing
                searchterms.add(targetMethod.getType().toString());
                if (isUsedInArguments(use, targetMethod.arguments())) {
                    term = prepareSearchTerm(Fields.USED_AS_TAGET_FOR_METHODS, optMethod.get());
                } else {
                    term = prepareSearchTerm(Fields.USED_AS_TAGET_FOR_METHODS, optMethod.get());
                }
                break;
            }
            case ASTNode.METHOD_INVOCATION:
                final MethodInvocation targetMethod = (MethodInvocation) astParent;
                final IMethodBinding methodBinding = targetMethod.resolveMethodBinding();
                final Optional<String> optMethod = BindingHelper.getIdentifier(methodBinding);
                if (!optMethod.isPresent()) {
                    break;
                }
                searchterms.add(targetMethod.getName().toString());
                if (isUsedInArguments(use, targetMethod.arguments())) {
                    term = prepareSearchTerm(Fields.USED_AS_TAGET_FOR_METHODS, optMethod.get());
                } else {
                    term = prepareSearchTerm(Fields.USED_AS_TAGET_FOR_METHODS, optMethod.get());
                }
                break;
            case ASTNode.SINGLE_VARIABLE_DECLARATION:
                term = prepareSearchTerm(Fields.VARIABLE_DEFINITION, Fields.DEFINITION_PARAMETER);
                break;
            case ASTNode.VARIABLE_DECLARATION_FRAGMENT:
                final VariableDeclarationFragment declParent = (VariableDeclarationFragment) use.getParent();

                final Expression initializer = declParent.getInitializer();
                Optional<Tuple<IMethod, String>> def = absent();
                if (initializer == null) {
                    term = prepareSearchTerm(Fields.VARIABLE_DEFINITION, Fields.DEFINITION_UNINITIALIZED);
                    break;
                } else {

                    switch (initializer.getNodeType()) {
                    case ASTNode.NULL_LITERAL:
                        term = prepareSearchTerm(Fields.VARIABLE_DEFINITION, Fields.DEFINITION_NULLLITERAL);
                        break;
                    case ASTNode.SUPER_METHOD_INVOCATION:
                        term = prepareSearchTerm(Fields.VARIABLE_DEFINITION, Fields.DEFINITION_ASSIGNMENT);
                        def = findMethod((SuperMethodInvocation) initializer);
                        break;
                    case ASTNode.METHOD_INVOCATION:
                        term = prepareSearchTerm(Fields.VARIABLE_DEFINITION, Fields.DEFINITION_ASSIGNMENT);
                        def = findMethod((MethodInvocation) initializer);
                        break;
                    case ASTNode.CLASS_INSTANCE_CREATION: {
                        term = prepareSearchTerm(Fields.VARIABLE_DEFINITION, Fields.DEFINITION_INSTANCE_CREATION);
                        def = findMethod((ClassInstanceCreation) initializer);
                        break;
                    }

                    case ASTNode.CAST_EXPRESSION:
                        // look more deeply into this here:
                        final Expression expression = ((CastExpression) initializer).getExpression();

                        switch (expression.getNodeType()) {
                        case ASTNode.METHOD_INVOCATION:
                            def = findMethod((MethodInvocation) expression);
                            break;
                        case ASTNode.SUPER_METHOD_INVOCATION:
                            def = findMethod((SuperMethodInvocation) expression);
                            break;
                        }
                    }
                    if (def.isPresent()) {
                        searchterms.add(def.get().getFirst().getElementName());
                        final TermQuery subquery = new TermQuery(
                                prepareSearchTerm(Fields.VARIABLE_DEFINITION, def.get().getSecond()));
                        subquery.setBoost(2);
                        query.add(subquery, Occur.SHOULD);
                    }
                }
                break;
            default:
                break;
            }
            if (term != null) {
                query.add(new TermQuery(term), Occur.SHOULD);
            }

        }
        return query;
    }

    private static Optional<Tuple<IMethod, String>> findMethod(final MethodInvocation s) {
        return findMethod(s.resolveMethodBinding());
    }

    private static Optional<Tuple<IMethod, String>> findMethod(final SuperMethodInvocation s) {
        return findMethod(s.resolveMethodBinding());
    }

    //    private static Optional<Tuple<IMethod, String>> findMethod(final ConstructorInvocation s) {
    //        return findMethod(s.resolveConstructorBinding());
    //    }

    private static Optional<Tuple<IMethod, String>> findMethod(final ClassInstanceCreation s) {
        return findMethod(s.resolveConstructorBinding());
    }

    private static Optional<Tuple<IMethod, String>> findMethod(final IMethodBinding b) {
        if (b == null) {
            return absent();
        }
        final IMethod method = (IMethod) b.getJavaElement();
        final Optional<String> opt = getIdentifier(b);
        if (method == null || !opt.isPresent()) {
            return absent();
        }
        return of(Tuple.newTuple(method, opt.get()));
    }

    private boolean isUsedInArguments(final SimpleName uses, final List arguments) {
        return arguments.size() == 0 || arguments.indexOf(uses) == -1;
    }

    private void startMeasurement() {
        watch = new Stopwatch();
        watch.start();
    }

    private void stopMeasurement() {
        watch.stop();
    }
}