/*******************************************************************************
* Copyright (c) 2005, 2006 IBM Corporation and others.
* 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:
* mkaufman@bea.com - initial API and implementation
* IBM - renamed from PreReconcileCompilationResult to ReconcileContext
* IBM - rewrote spec
*
*******************************************************************************/
package org.rubypeople.rdt.core.compiler;
import java.util.HashMap;
import org.jruby.ast.RootNode;
import org.rubypeople.rdt.core.IRubyElementDelta;
import org.rubypeople.rdt.core.IRubyModelMarker;
import org.rubypeople.rdt.core.IRubyScript;
import org.rubypeople.rdt.core.RubyModelException;
import org.rubypeople.rdt.internal.core.ReconcileWorkingCopyOperation;
import org.rubypeople.rdt.internal.core.RubyScript;
/**
* The context of a reconcile event that is notified to interested compilation
* participants while a reconcile operation is running.
* <p>
* A reconcile participant can get the AST for the reconcile-operation using
* {@link #getAST()}. If the participant modifies in any way the AST
* (either by modifying the source of the working copy, or modifying another entity
* that would result in different bindings for the AST), it is expected to reset the
* AST in the context using {@link #resetAST()}.
* </p><p>
* A reconcile participant can also create and return problems using
* {@link #putProblems(String, CategorizedProblem[])}. These problems are then reported
* to the problem requestor of the reconcile operation.
* </p><p>
* This class is not intended to be instanciated or subclassed by clients.
* </p>
*
* @see CompilationParticipant#reconcile(ReconcileContext)
* @since 0.9.0
*/
public class ReconcileContext {
private ReconcileWorkingCopyOperation operation;
private RubyScript workingCopy;
/**
* Creates a reconcile context for the given reconcile operation.
* <p>
* This constructor is not intended to be called by clients.
* </p>
*
* @param operation the reconcile operation
*/
public ReconcileContext(ReconcileWorkingCopyOperation operation, RubyScript workingCopy) {
this.operation = operation;
this.workingCopy = workingCopy;
}
/**
* Returns a resolved AST with {@link AST#JLS3 JLS3} level.
* It is created from the current state of the working copy.
* Creates one if none exists yet.
* Returns <code>null</code> if the current state of the working copy
* doesn't allow the AST to be created (e.g. if the working copy's content
* cannot be parsed).
* <p>
* If the AST level requested during reconciling is not {@link AST#JLS3}
* or if binding resolutions was not requested, then a different AST is created.
* Note that this AST does not become the current AST and it is only valid for
* the requestor.
* </p>
*
* @return the AST created from the current state of the working copy,
* or <code>null</code> if none could be created
* @exception RubyModelException if the contents of the working copy
* cannot be accessed. Reasons include:
* <ul>
* <li> The working copy does not exist (ELEMENT_DOES_NOT_EXIST)</li>
* </ul>
*/
public RootNode getAST() throws RubyModelException {
return this.operation.makeConsistent(this.workingCopy, null/*don't report problems to the working copy's problem requestor*/);
}
/**
* Returns the delta describing the change to the working copy being reconciled.
* Returns <code>null</code> if there is no change.
* Note that the delta's AST is not yet positionnned at this stage. Use {@link #getAST3()}
* to get the current AST.
*
* @return the delta describing the change, or <code>null</code> if none
*/
public IRubyElementDelta getDelta() {
return this.operation.deltaBuilder.delta;
}
/**
* Returns the problems to be reported to the problem requestor of the reconcile operation
* for the given marker type.
* Returns <code>null</code> if no problems need to be reported for this marker type.
*
* @param markerType the given marker type
* @return problems to be reported to the problem requesto
*/
public CategorizedProblem[] getProblems(String markerType) {
if (this.operation.problems == null) return null;
return (CategorizedProblem[]) this.operation.problems.get(markerType);
}
/**
* Returns the working copy this context refers to.
*
* @return the working copy this context refers to
*/
public IRubyScript getWorkingCopy() {
return this.workingCopy;
}
/**
* Resets the AST carried by this context.
* A compilation participant that modifies the environment that would result in different
* bindings for the AST is expected to reset the AST on this context, so that other
* participants don't get a stale AST.
* <p>
* Note that resetting the AST will not restart the reconcile process. Only further
* participants will see the new AST. Thus participants running before the one that
* resets the AST will have a stale view of the AST and its problems. Use
* the compilation participant extension point to order the participants.
* </p>
*/
public void resetAST() {
this.operation.ast = null;
putProblems(IRubyModelMarker.RUBY_MODEL_PROBLEM_MARKER, null);
putProblems(IRubyModelMarker.TASK_MARKER, null);
}
/**
* Sets the problems to be reported to the problem requestor of the reconcile operation
* for the given marker type.
* <code>null</code> indicates that no problems need to be reported.
* <p>
* Using this functionality, a participant that resolves problems for a given marker type
* can hide those problems since they don't exist any longer.
* </p>
*
* @param markerType the marker type of the given problems
* @param problems the problems to be reported to the problem requestor of the reconcile operation,
* or <code>null</code> if none
*/
public void putProblems(String markerType, CategorizedProblem[] problems) {
if (this.operation.problems == null)
this.operation.problems = new HashMap();
this.operation.problems.put(markerType, problems);
}
}