package jetbrains.mps.checkers;
/*Generated by MPS */
import org.jetbrains.mps.openapi.model.SNode;
import org.jetbrains.mps.openapi.module.SRepository;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SNodeOperations;
import org.jetbrains.mps.openapi.module.SModule;
import jetbrains.mps.resolve.ReferenceResolverUtils;
import org.jetbrains.mps.openapi.model.SReference;
import jetbrains.mps.lang.smodel.generator.smodelAdapter.SLinkOperations;
import jetbrains.mps.smodel.constraints.ReferenceDescriptor;
import jetbrains.mps.smodel.constraints.ModelConstraints;
import jetbrains.mps.scope.Scope;
import jetbrains.mps.scope.ErrorScope;
import jetbrains.mps.errors.messageTargets.ReferenceMessageTarget;
import jetbrains.mps.smodel.runtime.ReferenceScopeProvider;
import org.jetbrains.mps.openapi.model.SNodeReference;
import jetbrains.mps.errors.QuickFixProvider;
import jetbrains.mps.errors.QuickFix_Runtime;
import jetbrains.mps.resolve.ResolverComponent;
public class RefScopeChecker extends AbstractNodeChecker {
public RefScopeChecker() {
}
@Override
public void checkNode(SNode node, LanguageErrorsCollector errorsCollector, SRepository repository) {
if (node == null || SNodeOperations.getModel(node) == null) {
return;
}
SModule module = SNodeOperations.getModel(node).getModule();
if (module == null) {
return;
}
boolean executeImmediately = ReferenceResolverUtils.canExecuteImmediately(SNodeOperations.getModel(node), repository);
for (SReference ref : SNodeOperations.getReferences(node)) {
SNode target = SLinkOperations.getTargetNode(ref);
if (target == null) {
continue;
}
// don't check unresolved and broken references, they should already have an error message
// do we need all these additional dependencies? mb. it's better to use .runcheckingAction() instead?
errorsCollector.addDependency(target);
errorsCollector.addDependency(SNodeOperations.getParent(node));
for (SNode c : SNodeOperations.getChildren(node)) {
errorsCollector.addDependency(c);
}
ReferenceDescriptor refDescriptor = ModelConstraints.getReferenceDescriptor(ref);
Scope refScope = refDescriptor.getScope();
if (refScope instanceof ErrorScope) {
errorsCollector.addError(node, ((ErrorScope) refScope).getMessage(), null, new ReferenceMessageTarget(SLinkOperations.getRefLink(ref).getName()));
} else if (!(refScope.contains(target))) {
String name = target.getName();
ReferenceScopeProvider scopeProvider = refDescriptor.getScopeProvider();
SNodeReference ruleNode = null;
if (scopeProvider != null) {
ruleNode = scopeProvider.getSearchScopeValidatorNode();
}
errorsCollector.addError(node, "reference" + ((name == null ? "" : " " + name)) + " (" + SLinkOperations.getRefLink(ref).getName() + ") is out of search scope", ruleNode, new ReferenceMessageTarget(SLinkOperations.getRefLink(ref).getName()), createResolveReferenceQuickfix(ref, repository, executeImmediately));
}
}
}
protected QuickFixProvider createResolveReferenceQuickfix(SReference reference, SRepository repository, boolean executeImmediately) {
return new RefScopeChecker.ResolveReferenceQuickFix(reference, repository, executeImmediately);
}
protected class ResolveReferenceQuickFix implements QuickFixProvider {
private boolean myIsError;
protected SReference myReference;
protected SRepository myRepository;
private boolean myExecuteImmediately;
public ResolveReferenceQuickFix(SReference reference, SRepository repository, boolean executeImmediately) {
myReference = reference;
myRepository = repository;
myExecuteImmediately = executeImmediately;
}
@Override
public QuickFix_Runtime getQuickFix() {
return new QuickFix_Runtime() {
@Override
public void execute(SNode node) {
ResolverComponent.getInstance().resolve(myReference, myRepository);
}
@Override
public String getDescription(SNode node) {
return "Resolve \"" + myReference.getLink().getName() + "\" reference";
}
};
}
@Override
public boolean isExecutedImmediately() {
return myExecuteImmediately;
}
@Override
public void setIsError(boolean isError) {
myIsError = isError;
}
@Override
public boolean isError() {
return myIsError;
}
}
}