/* * Copyright (c) 2011, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.core.completion; import com.google.dart.tools.core.problem.Problem; /** * The abstract class <code>CompletionRequestor</code> defines the behavior common to objects that * represent a completion requestor which is passed completion proposals as they are generated in * response to a code assist request. * <p> * This class is intended to be subclassed by clients. * <p> * The code assist engine normally invokes methods on completion requestor in the following * sequence: * * <pre> * requestor.beginReporting(); * requestor.acceptContext(context); * requestor.accept(proposal_1); * requestor.accept(proposal_2); * ... * requestor.endReporting(); * </pre> * If, however, the engine is unable to offer completion proposals for whatever reason, * <code>completionFailure</code> is called with a problem object describing why completions were * unavailable. In this case, the sequence of calls is: * * <pre> * requestor.beginReporting(); * requestor.acceptContext(context); * requestor.completionFailure(problem); * requestor.endReporting(); * </pre> * In either case, the bracketing <code>beginReporting</code> <code>endReporting</code> calls are * always made as well as <code>acceptContext</code> call. * * @coverage dart.tools.core.completion */ public abstract class CompletionRequestor { /** * The set of CompletionProposal kinds that this requestor ignores; <code>0</code> means the set * is empty. 1 << completionProposalKind */ private int ignoreSet = 0; private String[] favoriteReferences; /** * The set of CompletionProposal kinds that this requestor allows for required proposals; * <code>0</code> means the set is empty. 1 << completionProposalKind */ private int requiredProposalAllowSet[] = null; private boolean requireExtendedContext = false; /** * Initialize a newly created completion requestor. The requestor is interested in all kinds of * completion proposals; none will be ignored. Calls to this constructor are identical to calls to * <code>CompletionRequestor(false)</code> */ public CompletionRequestor() { this(false); } /** * Initialize a newly created completion requestor. If <code>ignoreAll</code> is <code>true</code> * the requestor is not interested in all kinds of completion proposals; all will be ignored. For * each kind of completion proposals that is of interest, <code>setIgnored(kind, false)</code> * must be called. If <code>ignoreAll</code> is <code>false</code> the requestor is interested in * all kinds of completion proposals; none will be ignored. * * @param ignoreAll <code>true</code> to ignore all kinds of completion proposals, and * <code>false</code> to propose all kinds */ public CompletionRequestor(boolean ignoreAll) { ignoreSet = ignoreAll ? 0xffffffff : 0x00000000; } /** * Proposes a completion. Has no effect if the kind of proposal is being ignored by this * requestor. Callers should consider checking {@link #isIgnored(int)} before avoid creating * proposal objects that would only be ignored. * <p> * Similarly, implementers should check {@link #isIgnored(int) isIgnored(proposal.getKind())} and * ignore proposals that have been declared as uninteresting. The proposal object passed is only * valid for the duration of completion operation. * * @param proposal the completion proposal * @throws IllegalArgumentException if the proposal is null */ public abstract void accept(CompletionProposal proposal); /** * Propose the context in which the completion occurs. * <p> * This method is called one and only one time before any call to * {@link #accept(CompletionProposal)}. The default implementation of this method does nothing. * Clients may override. * * @param context the completion context */ public void acceptContext(CompletionContext context) { // do nothing } /** * Pro forma notification sent before reporting a batch of completion proposals. * <p> * The default implementation of this method does nothing. Clients may override. */ public void beginReporting() { // do nothing } /** * Notification of failure to produce any completions. The problem object explains what prevented * completing. * <p> * The default implementation of this method does nothing. Clients may override to receive this * kind of notice. * * @param problem the problem object */ public void completionFailure(Problem problem) { // default behavior is to ignore } /** * Pro forma notification sent after reporting a batch of completion proposals. * <p> * The default implementation of this method does nothing. Clients may override. */ public void endReporting() { // do nothing } /** * Return the favorite references which are used to compute some completion proposals. * <p> * A favorite reference is a qualified reference as it can be seen in an import statement.<br> * e.g. <code>{"java.util.Arrays"}</code><br> * It can be an on demand reference.<br> * e.g. <code>{"java.util.Arrays.*"}</code> It can be a reference to a static method or field (as * in a static import)<br> * e.g. <code>{"java.util.Arrays.equals"}</code> * <p> * Currently only on demand type references (<code>"java.util.Arrays.*"</code> ), references to a * static method or a static field are used to compute completion proposals. Other kind of * reference could be used in the future. * </p> * * @return favorite imports */ @Deprecated public String[] getFavoriteReferences() { return favoriteReferences; } public abstract com.google.dart.engine.ast.CompilationUnit getInputUnit(); /** * Return <code>true</code> if a proposal of a given kind with a required proposal of the given * kind is allowed. * * @param proposalKind one of the kind constants declared * @param requiredProposalKind one of the kind constants declared on * <code>CompletionProposal</code> * @return <code>true</code> if a proposal of a given kind with a required proposal of the given * kind is allowed by this requestor, and <code>false</code> if it isn't of interest. * <p> * By default, all kinds of required proposals aren't allowed. * @see #setAllowsRequiredProposals(int, int, boolean) * @see CompletionProposal#getKind() * @see CompletionProposal#getRequiredProposals() */ public boolean isAllowingRequiredProposals(int proposalKind, int requiredProposalKind) { if (proposalKind < CompletionProposal.FIRST_KIND || proposalKind > CompletionProposal.LAST_KIND) { throw new IllegalArgumentException( "Unknown kind of completion proposal: " + requiredProposalKind); //$NON-NLS-1$ } if (requiredProposalKind < CompletionProposal.FIRST_KIND || requiredProposalKind > CompletionProposal.LAST_KIND) { throw new IllegalArgumentException( "Unknown required kind of completion proposal: " + requiredProposalKind); //$NON-NLS-1$ } if (requiredProposalAllowSet == null) { return false; } return 0 != (requiredProposalAllowSet[proposalKind] & (1 << requiredProposalKind)); } /** * Return <code>true</code> if this requestor requires an extended context. By default this method * return <code>false</code>. * * @return <code>true</code> if this requestor requires an extended context. * @see CompletionContext#isExtended() */ public boolean isExtendedContextRequired() { return requireExtendedContext; } /** * Return <code>true</code> if the given kind of completion proposal is ignored. * * @param completionProposalKind one of the kind constants declared on * <code>CompletionProposal</code> * @return <code>true</code> if the given kind of completion proposal is ignored by this * requestor, and <code>false</code> if it is of interest * @see #setIgnored(int, boolean) * @see CompletionProposal#getKind() */ public boolean isIgnored(int completionProposalKind) { if (completionProposalKind < CompletionProposal.FIRST_KIND || completionProposalKind > CompletionProposal.LAST_KIND) { throw new IllegalArgumentException( "Unknown kind of completion proposal: " + completionProposalKind); //$NON-NLS-1$ } return 0 != (ignoreSet & (1 << completionProposalKind)); } /** * Set whether a proposal of a given kind with a required proposal of the given kind is allowed. * <p> * A required proposal of a given kind is proposed even if {@link #isIgnored(int)} return * <code>true</code> for that kind. * <p> * Currently only a subset of kinds support required proposals. To see what combinations are * supported you must look at {@link CompletionProposal#getRequiredProposals()} documentation. * * @param proposalKind one of the kind constants declared * @param requiredProposalKind one of the kind constants declared on * <code>CompletionProposal</code> * @param allow <code>true</code> if a proposal of a given kind with a required proposal of the * given kind is allowed by this requestor, and <code>false</code> if it isn't of * interest * @see #isAllowingRequiredProposals(int, int) * @see CompletionProposal#getKind() * @see CompletionProposal#getRequiredProposals() */ public void setAllowsRequiredProposals(int proposalKind, int requiredProposalKind, boolean allow) { if (proposalKind < CompletionProposal.FIRST_KIND || proposalKind > CompletionProposal.LAST_KIND) { throw new IllegalArgumentException( "Unknown kind of completion proposal: " + requiredProposalKind); //$NON-NLS-1$ } if (requiredProposalKind < CompletionProposal.FIRST_KIND || requiredProposalKind > CompletionProposal.LAST_KIND) { throw new IllegalArgumentException( "Unknown required kind of completion proposal: " + requiredProposalKind); //$NON-NLS-1$ } if (requiredProposalAllowSet == null) { requiredProposalAllowSet = new int[CompletionProposal.LAST_KIND + 1]; } if (allow) { requiredProposalAllowSet[proposalKind] |= (1 << requiredProposalKind); } else { requiredProposalAllowSet[proposalKind] &= ~(1 << requiredProposalKind); } } /** * Set the favorite references which will be used to compute some completion proposals. A favorite * reference is a qualified reference as it can be seen in an import statement.<br> * * @param favoriteImports * @see #getFavoriteReferences() */ public void setFavoriteReferences(String[] favoriteImports) { favoriteReferences = favoriteImports; } /** * Sets whether the given kind of completion proposal is ignored. * * @param completionProposalKind one of the kind constants declared on * <code>CompletionProposal</code> * @param ignore <code>true</code> if the given kind of completion proposal is ignored by this * requestor, and <code>false</code> if it is of interest * @see #isIgnored(int) * @see CompletionProposal#getKind() */ public void setIgnored(int completionProposalKind, boolean ignore) { if (completionProposalKind < CompletionProposal.FIRST_KIND || completionProposalKind > CompletionProposal.LAST_KIND) { throw new IllegalArgumentException( "Unknown kind of completion proposal: " + completionProposalKind); //$NON-NLS-1$ } if (ignore) { ignoreSet |= (1 << completionProposalKind); } else { ignoreSet &= ~(1 << completionProposalKind); } } /** * Set whether this requestor requires an extended context. * * @param require <code>true</code> if this requestor requires an extended context * @see CompletionContext#isExtended() */ public void setRequireExtendedContext(boolean require) { requireExtendedContext = require; } }