/* * Copyright (c) 2012 Andrejs Jermakovics. * * 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: * Andrejs Jermakovics - initial implementation */ package jmockit.assist; import static jmockit.assist.MockUtil.findMockedTypeFromNode; import static org.eclipse.jface.viewers.StyledString.QUALIFIER_STYLER; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.NodeFinder; import org.eclipse.jdt.internal.ui.JavaPluginImages; import org.eclipse.jdt.internal.ui.text.java.JavaCompletionProposal; import org.eclipse.jdt.ui.text.java.ContentAssistInvocationContext; import org.eclipse.jdt.ui.text.java.IInvocationContext; import org.eclipse.jdt.ui.text.java.IJavaCompletionProposal; import org.eclipse.jdt.ui.text.java.IJavaCompletionProposalComputer; import org.eclipse.jdt.ui.text.java.IProblemLocation; import org.eclipse.jdt.ui.text.java.IQuickAssistProcessor; import org.eclipse.jdt.ui.text.java.JavaContentAssistInvocationContext; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.jface.text.contentassist.IContextInformation; import org.eclipse.jface.viewers.StyledString; import org.eclipse.swt.graphics.Image; @SuppressWarnings("restriction") /** * Computes proposals for mock methods in mock objects */ public class JmockitProposalComputer implements IJavaCompletionProposalComputer, IQuickAssistProcessor { private String fErrorMessage; public JmockitProposalComputer() {// } @Override public final List<ICompletionProposal> computeCompletionProposals(final ContentAssistInvocationContext context, final IProgressMonitor mon) { ITypeBinding mockType = null, paramType = null; ICompilationUnit cunit = getCompilationUnit(context); CompilationUnit astRoot = null; if (cunit != null) { astRoot = ASTUtil.getAstOrParse(cunit, mon); if( astRoot != null ) { ASTNode node = NodeFinder.perform(astRoot, context.getInvocationOffset(), 1); mockType = MockUtil.getMockType(node); paramType = findMockedTypeFromNode(node); } } if ( paramType != null && mockType != null ) { try { return getProposals(context, paramType, cunit, mockType, astRoot.getAST()); } catch (Exception e) { fErrorMessage = e.getMessage(); Activator.log(e); } } return Collections.emptyList(); } public final ICompilationUnit getCompilationUnit(final ContentAssistInvocationContext context) { ICompilationUnit cunit = null; if (context instanceof JavaContentAssistInvocationContext) { JavaContentAssistInvocationContext jcontext = (JavaContentAssistInvocationContext) context; if (jcontext.getCoreContext() != null) { cunit = jcontext.getCompilationUnit(); } } return cunit; } private List<ICompletionProposal> getProposals(final ContentAssistInvocationContext context, final ITypeBinding paramType, final ICompilationUnit cunit, final ITypeBinding mockType, final AST ast) throws JavaModelException, BadLocationException { Collection<IJavaCompletionProposal> list = new ArrayList<IJavaCompletionProposal>(); String prefix = context.computeIdentifierPrefix().toString(); Set<String> existingMethods = ASTUtil.getMethodSignatures(mockType); addClinitProposal(context, paramType, mockType, list, prefix); addItFieldProposal(context, paramType, mockType, list, prefix); for (final IMethodBinding meth : ASTUtil.getAllMethods(paramType, ast) ) { String methodName = meth.getName(); if( !methodName.startsWith(prefix) || "<clinit>".equals(methodName) ) { continue; } String methSig = ASTUtil.getSig(meth); methodName = meth.isConstructor() ? MockUtil.CTOR : meth.getName(); if( existingMethods.contains(methSig) ) { continue; } try { MockMethodCompletionProposal proposal = createMockMethodProposal(context, paramType, cunit, prefix, meth, methodName); list.add(proposal); } catch (Exception e) { Activator.log(e); } } return new ArrayList<ICompletionProposal>(list); } private void addClinitProposal(final ContentAssistInvocationContext context, final ITypeBinding paramType, final ITypeBinding mockType, final Collection<IJavaCompletionProposal> list, final String prefix) { boolean hasClinit = false; for(IMethodBinding method : mockType.getDeclaredMethods()) { if( MockUtil.CLASSINIT.equals( method.getName() ) ) { hasClinit = true; break; } } if( !hasClinit ) { StyledString displayName = new StyledString(MockUtil.CLASSINIT + "() : void"); displayName.append(" - Mock class initialisers of '" + paramType.getName() +"'", QUALIFIER_STYLER); StringBuffer buffer = new StringBuffer(); buffer.append("@Mock "); buffer.append("void ").append(MockUtil.CLASSINIT).append("()"); buffer.append(" { }"); IJavaCompletionProposal proposal = new JavaCompletionProposal(buffer.toString(), context.getInvocationOffset()-prefix.length(), prefix.length(), JavaPluginImages.get(JavaPluginImages.IMG_MISC_DEFAULT), displayName, MockMethodCompletionProposal.METHOD_RELEVANCE); list.add( proposal ); } } private void addItFieldProposal(final ContentAssistInvocationContext context, final ITypeBinding paramType, final ITypeBinding mockType, final Collection<IJavaCompletionProposal> list, final String prefix) throws JavaModelException { boolean hasItField = false; for(IVariableBinding field : mockType.getDeclaredFields()) { if( "it".equals( field.getName() ) ) { hasItField = true; break; } } if( !hasItField && "it".startsWith(prefix) ) { String relpacement = paramType.getName() + " it;"; Image image = JavaPluginImages.get(JavaPluginImages.IMG_FIELD_DEFAULT); StyledString displayName = new StyledString("it : " + paramType.getName()); displayName.append(" - Access the mocked object 'it' of type '" + paramType.getName() +"'", QUALIFIER_STYLER); IJavaCompletionProposal proposal = new JavaCompletionProposal(relpacement, context.getInvocationOffset()-prefix.length(), prefix.length(), image, displayName, MockMethodCompletionProposal.MAX_RELEVANCE); list.add(proposal ); } } private MockMethodCompletionProposal createMockMethodProposal(final ContentAssistInvocationContext context, final ITypeBinding paramType, final ICompilationUnit cunit, final String prefix, final IMethodBinding meth, final String methodName) throws JavaModelException { String params = getParameters(meth); StyledString displayName = new StyledString(methodName + "(" + params + ") : " + meth.getReturnType().getName() ); String desc = meth.isConstructor() ? "constructor" : "method"; displayName.append(" - Mock " + desc + " of '" + paramType.getName() +"'", QUALIFIER_STYLER); String completionProposal = meth.getReturnType().getName() + " " + methodName; MockMethodCompletionProposal proposal = new MockMethodCompletionProposal(cunit, meth, context.getInvocationOffset()-prefix.length(), prefix.length(), displayName, completionProposal); return proposal; } private String getParameters(final IMethodBinding methBinding) throws JavaModelException { IMethod meth = (IMethod) methBinding.getJavaElement(); if( meth == null ) return ""; String[] paramNames = meth.getParameterNames(); String params= ""; ITypeBinding[] paramTypes = methBinding.getParameterTypes(); for(int i = 0; i < paramTypes.length; i++) { String par = paramTypes[i].getName(); if( i != 0 ) { params += ", "; } try { params += par; //Signature.getSimpleName( Signature.toString(par) ); } catch(Exception e) { Activator.log(e); params += par; } params += " " + paramNames[i]; } return params; } // public static Set<String> getObjectMethods(final IJavaProject jproj) throws JavaModelException // { // IType objType = jproj.findType("java.lang.Object"); // // return getTypeMethods(objType); // } @Override public final List<IContextInformation> computeContextInformation(final ContentAssistInvocationContext ctx, final IProgressMonitor mon) { return Collections.emptyList(); } @Override public final String getErrorMessage() { return fErrorMessage; } @Override public final void sessionEnded() { } @Override public final void sessionStarted() { } @Override public final boolean hasAssists(final IInvocationContext context) throws CoreException { //System.err.println("has assist? "); return false; } @Override public final IJavaCompletionProposal[] getAssists(final IInvocationContext context, final IProblemLocation[] locations) throws CoreException { //System.err.println("get assist"); return new IJavaCompletionProposal[]{}; } }