@Override public List<ICompletionProposal> computeCompletionProposals( final ContentAssistInvocationContext context, final IProgressMonitor monitor) { final List<ICompletionProposal> list = new ArrayList<ICompletionProposal>(); boolean extendContext = false; try { if (context instanceof JavaContentAssistInvocationContext) { final ITextViewer viewer = context.getViewer(); final List<ScriptVariable> scriptVariables = getScriptVariables(viewer); if (scriptVariables.isEmpty()) { return list; } final CompletionContext coreContext = ((JavaContentAssistInvocationContext) context).getCoreContext(); if (coreContext != null && !coreContext.isExtended()) { // must use reflection to set the fields ReflectionUtils.setPrivateField( InternalCompletionContext.class, "isExtended", coreContext, true); extendContext = true; } final ICompilationUnit unit = ((JavaContentAssistInvocationContext) context).getCompilationUnit(); if (unit instanceof GroovyCompilationUnit) { if (((GroovyCompilationUnit) unit).getModuleNode() == null) { return Collections.emptyList(); } final ContentAssistContext assistContext = new GroovyCompletionProposalComputer() .createContentAssistContext( (GroovyCompilationUnit) unit, context.getInvocationOffset(), context.getDocument()); CharSequence prefix = null; try { prefix = context.computeIdentifierPrefix(); } catch (final BadLocationException e) { BonitaStudioLog.error(e); } if (assistContext != null && assistContext.completionNode instanceof VariableExpression) { try { final VariableExpression expr = (VariableExpression) assistContext.completionNode; if (scriptVariables != null) { for (final ScriptVariable f : scriptVariables) { if (expr.getName().equals(f.getName())) { final IType type = javaProject.findType(f.getType()); if (type == null) { return list; } for (final IMethod m : type.getMethods()) { if (m.getElementName().startsWith(prefix.toString())) { final GroovyCompletionProposal proposal = new GroovyCompletionProposal( CompletionProposal.METHOD_REF, context.getInvocationOffset()); proposal.setName(m.getElementName().toCharArray()); proposal.setCompletion( m.getElementName().substring(prefix.length()).toCharArray()); proposal.setFlags(m.getFlags()); if (prefix.length() == m.getElementName().length()) { proposal.setReplaceRange( context.getInvocationOffset(), context.getInvocationOffset()); proposal.setReceiverRange(0, 0); } else { proposal.setReplaceRange( context.getInvocationOffset() - prefix.length(), context.getInvocationOffset()); proposal.setReceiverRange(prefix.length(), prefix.length()); } final char[][] parametersArray = new char[m.getParameterNames().length][256]; final List<Parameter> parameters = new ArrayList<Parameter>(); for (int i = 0; i < m.getParameterNames().length; i++) { parametersArray[i] = m.getParameterNames()[i].toCharArray(); parameters.add( new Parameter( ClassHelper.make( Signature.getSignatureSimpleName(m.getParameterTypes()[i])), m.getParameterNames()[i])); } final ClassNode classNode = ClassHelper.make(m.getDeclaringType().getFullyQualifiedName()); proposal.setDeclarationSignature( ProposalUtils.createTypeSignature(classNode)); proposal.setParameterNames(parametersArray); if (m.getDeclaringType().getFullyQualifiedName().equals(f.getType())) { proposal.setRelevance(100); } final MethodNode methodNode = new MethodNode( m.getElementName(), m.getFlags(), ClassHelper.make( Signature.getSignatureSimpleName(m.getReturnType())), parameters.toArray(new Parameter[parameters.size()]), new ClassNode[0], null); final char[] methodSignature = ProposalUtils.createMethodSignature(methodNode); proposal.setSignature(methodSignature); final GroovyJavaGuessingCompletionProposal groovyProposal = GroovyJavaGuessingCompletionProposal.createProposal( proposal, (JavaContentAssistInvocationContext) context, true, "Groovy", ProposalFormattingOptions.newFromOptions()); if (groovyProposal != null) { list.add(groovyProposal); } } } } } } } catch (final JavaModelException e) { BonitaStudioLog.error(e); } } } return list; } } finally { final CompletionContext coreContext = ((JavaContentAssistInvocationContext) context).getCoreContext(); if (extendContext && coreContext != null && coreContext.isExtended()) { // must use reflection to set the fields ReflectionUtils.setPrivateField( InternalCompletionContext.class, "isExtended", coreContext, false); } } return Collections.emptyList(); }
/** * @author andrew * @created Nov 17, 2010 */ public class MethodContributionElement implements IContributionElement { private static final BlockStatement EMPTY_BLOCK = new BlockStatement(); private static final ClassNode[] NO_EXCEPTIONS = new ClassNode[0]; private static final Parameter[] NO_PARAMETERS = new Parameter[0]; private static final ParameterContribution[] NO_PARAMETER_CONTRIBUTION = new ParameterContribution[0]; private static final ClassNode UNKNOWN_TYPE = ClassHelper.DYNAMIC_TYPE; private final String methodName; private final ParameterContribution[] params; private final ParameterContribution[] namedParams; private final ParameterContribution[] optionalParams; private final String returnType; private final String declaringType; private final boolean isStatic; private final boolean useNamedArgs; private final String provider; private final String doc; private ClassNode cachedDeclaringType; private ClassNode cachedReturnType; private Parameter[] cachedRegularParameters; private Parameter[] cachedNamedParameters; private Parameter[] cachedOptionalParameters; private ProposalFormattingOptions options = ProposalFormattingOptions.newFromOptions(); private final int relevanceMultiplier; private final boolean isDeprecated; public MethodContributionElement( String methodName, ParameterContribution[] params, String returnType, String declaringType, boolean isStatic, String provider, String doc, boolean useNamedArgs, boolean isDeprecated, int relevanceMultiplier) { this( methodName, params, NO_PARAMETER_CONTRIBUTION, NO_PARAMETER_CONTRIBUTION, returnType, declaringType, isStatic, provider, doc, useNamedArgs, isDeprecated, relevanceMultiplier); } public MethodContributionElement( String methodName, ParameterContribution[] params, ParameterContribution[] namedParams, ParameterContribution[] optionalParams, String returnType, String declaringType, boolean isStatic, String provider, String doc, boolean useNamedArgs, boolean isDeprecated, int relevanceMultiplier) { this.methodName = methodName; this.params = params; this.namedParams = namedParams; this.optionalParams = optionalParams; this.returnType = returnType; this.isStatic = isStatic; this.declaringType = declaringType; this.useNamedArgs = useNamedArgs; this.isDeprecated = isDeprecated; this.relevanceMultiplier = relevanceMultiplier; this.provider = provider == null ? GROOVY_DSL_PROVIDER : provider; this.doc = doc == null ? NO_DOC + this.provider : doc; } public TypeAndDeclaration lookupType( String name, ClassNode declaringType, ResolverCache resolver) { if (name.equals(methodName)) return new TypeAndDeclaration( ensureReturnType(resolver), toMethod(declaringType, resolver), ensureDeclaringType(declaringType, resolver), doc); else return null; } public IGroovyProposal toProposal(ClassNode declaringType, ResolverCache resolver) { GroovyMethodProposal groovyMethodProposal = new GroovyMethodProposal(toMethod(declaringType.redirect(), resolver), provider, options); groovyMethodProposal.setUseNamedArguments(useNamedArgs); groovyMethodProposal.setRelevanceMultiplier(relevanceMultiplier); return groovyMethodProposal; } public List<IGroovyProposal> extraProposals( ClassNode declaringType, ResolverCache resolver, Expression expression) { // first find the arguments that are possible Map<String, ClassNode> availableParams = findAvailableParamNames(resolver); if (availableParams.isEmpty()) { return ProposalUtils.NO_PROPOSALS; } if (expression instanceof MethodCallExpression) { // next find out if there are any existing named args MethodCallExpression call = (MethodCallExpression) expression; Expression arguments = call.getArguments(); if (arguments instanceof TupleExpression) { for (Expression maybeArg : ((TupleExpression) arguments).getExpressions()) { if (maybeArg instanceof MapExpression) { arguments = maybeArg; break; } } } // now remove the arguments that are already written if (arguments instanceof MapExpression) { // Do extra filtering to determine what parameters are still available MapExpression enclosingCallArgs = (MapExpression) arguments; for (MapEntryExpression entry : enclosingCallArgs.getMapEntryExpressions()) { String paramName = entry.getKeyExpression().getText(); availableParams.remove(paramName); } } } List<IGroovyProposal> extraProposals = new ArrayList<IGroovyProposal>(availableParams.size()); for (Entry<String, ClassNode> available : availableParams.entrySet()) { extraProposals.add( new GroovyNamedArgumentProposal( available.getKey(), available.getValue(), toMethod(declaringType.redirect(), resolver), provider)); } return extraProposals; } /** * @param resolver * @return */ private Map<String, ClassNode> findAvailableParamNames(ResolverCache resolver) { Map<String, ClassNode> available = new HashMap<String, ClassNode>(params.length); if (useNamedArgs) { for (ParameterContribution param : params) { available.put(param.name, param.toParameter(resolver).getType()); } } for (ParameterContribution param : namedParams) { available.put(param.name, param.toParameter(resolver).getType()); } for (ParameterContribution param : optionalParams) { available.put(param.name, param.toParameter(resolver).getType()); } return available; } private MethodNode toMethod(ClassNode declaringType, ResolverCache resolver) { if (cachedRegularParameters == null) { cachedRegularParameters = initParams(params, resolver); cachedOptionalParameters = initParams(optionalParams, resolver); cachedNamedParameters = initParams(namedParams, resolver); if (cachedReturnType == null) { if (resolver != null) { cachedReturnType = resolver.resolve(returnType); } else { cachedReturnType = VariableScope.OBJECT_CLASS_NODE; } } } MethodNode meth = new NamedArgsMethodNode( methodName, opcode(), cachedReturnType, cachedRegularParameters, cachedNamedParameters, cachedOptionalParameters, NO_EXCEPTIONS, EMPTY_BLOCK); meth.setDeclaringClass(ensureDeclaringType(declaringType, resolver)); return meth; } private Parameter[] initParams(ParameterContribution[] pcs, ResolverCache resolver) { Parameter[] ps; if (pcs == null) { ps = NO_PARAMETERS; } else { ps = new Parameter[pcs.length]; for (int i = 0; i < pcs.length; i++) { ps[i] = pcs[i].toParameter(resolver); } } return ps; } protected ClassNode ensureReturnType(ResolverCache resolver) { if (cachedReturnType == null) { cachedReturnType = resolver.resolve(returnType); } return cachedReturnType == null ? UNKNOWN_TYPE : cachedReturnType; } protected ClassNode ensureDeclaringType(ClassNode lexicalDeclaringType, ResolverCache resolver) { if (declaringType != null && cachedDeclaringType == null) { cachedDeclaringType = resolver.resolve(declaringType); } return cachedDeclaringType == null ? lexicalDeclaringType : cachedDeclaringType; } protected int opcode() { int modifiers = isStatic ? Opcodes.ACC_STATIC : Opcodes.ACC_PUBLIC; modifiers |= isDeprecated ? Opcodes.ACC_DEPRECATED : 0; return modifiers; } public String contributionName() { return methodName; } public String description() { return "Method: " + declaringType + "." + methodName + "(..)"; } public String getDeclaringTypeName() { return declaringType; } @Override public String toString() { return "public " + (isStatic ? "static " : "") + (isDeprecated ? "deprecated " : "") + (useNamedArgs ? "useNamedArgs " : "") + returnType + " " + declaringType + "." + methodName + "(" + Arrays.toString(params) + ") (" + provider + ")"; } }