/*
* Copyright 2003-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
*
* 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 jetbrains.mps.generator.impl.dependencies;
import jetbrains.mps.generator.TransientModelsModule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.mps.openapi.model.SModel;
import org.jetbrains.mps.openapi.model.SNode;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
/**
* Evgeny Gryaznov, May 11, 2010
*/
public class RootDependenciesBuilder implements DependenciesReadListener {
private final SNode myOriginalRoot;
private final IncrementalDependenciesBuilder myBuilder;
private final String myHash;
private boolean isUnchanged;
private boolean dependsOnModelNodes = false;
private boolean dependsOnConditionals = false;
private Set<SNode> dependsOn = new HashSet<SNode>();
private Set<SModel> dependsOnModels = new HashSet<SModel>();
private GenerationRootDependencies mySavedDependencies;
public RootDependenciesBuilder(@Nullable SNode originalRoot, @NotNull IncrementalDependenciesBuilder builder, @Nullable String hash) {
myOriginalRoot = originalRoot;
myBuilder = builder;
myHash = hash;
isUnchanged = false;
}
private void addNodeAccess(SNode node) {
SNode root = myBuilder.currentToOriginalMap.get(node);
if (root == null) {
dependsOnConditionals = true;
return;
}
if (root == myOriginalRoot) {
return;
}
dependsOn.add(root);
}
private void addOriginalNodeAccess(SNode root) {
if (root == myOriginalRoot || root.getModel() != myBuilder.originalInputModel || !(root.getModel() != null && root.getParent() == null)) {
return;
}
dependsOn.add(root);
}
private void addOutputNodeAccess(SNode node) {
if (myBuilder.nextStepToOriginalMap == null || myBuilder.currentOutputModel == null) {
return;
}
SNode root = myBuilder.nextStepToOriginalMap.get(node);
if (root == null) {
dependsOnConditionals = true;
return;
}
if (root == myOriginalRoot) {
return;
}
dependsOn.add(root);
}
private void addModelAccess(SModel model) {
if (model == null || model .getModule() instanceof TransientModelsModule) {
return;
}
assert model != myBuilder.currentInputModel && model != myBuilder.originalInputModel;
dependsOnModels.add(model);
myBuilder.reportModelAccess(model, myOriginalRoot);
}
@Override
public void readNode(SNode node) {
SModel model = node.getModel();
if (model != null) {
if (model == myBuilder.currentInputModel) {
addNodeAccess(node.getContainingRoot());
} else if (model == myBuilder.currentOutputModel) {
addOutputNodeAccess(node.getContainingRoot());
} else if (model == myBuilder.originalInputModel) {
addOriginalNodeAccess(node.getContainingRoot());
} else {
addModelAccess(model);
}
}
}
@Override
public void nodeChildReadAccess(SNode node, String childRole, SNode child) {
assert false : "SNode doesn't send nodeChildReadAccess any more";
}
@Override
public void nodePropertyReadAccess(SNode node, String propertyName, String value) {
// no-op
// properties read after node accessed give no additional information,
// properties read without access to owning node are likely to come from
// template (e.g. reading PropertyMacro.propertyName during expandPropertyMacro)
// or structure models (e.g. NameUtil.nodeFQName(node.concept))
}
@Override
public void propertyExistenceAccess(SNode node, String propertyName) {
assert false : "Dispatched only from NodeReadAccessCasterInEditor";
}
@Override
public void propertyDirtyReadAccess(SNode node, String propertyName) {
assert false : "Dispatched only from NodeReadAccessCasterInEditor";
}
@Override
public void propertyCleanReadAccess(SNode node, String propertyName) {
assert false : "Dispatched only from NodeReadAccessCasterInEditor";
}
@Override
public void nodeReferentReadAccess(SNode node, String referentRole, SNode referent) {
SModel model = node.getModel();
if (model != null) {
if (model == myBuilder.currentInputModel) {
addNodeAccess(node.getContainingRoot());
} else if (model == myBuilder.currentOutputModel) {
addOutputNodeAccess(node.getContainingRoot());
} else if (model == myBuilder.originalInputModel) {
addOriginalNodeAccess(node.getContainingRoot());
} else {
addModelAccess(model);
}
}
// FIXME read referent?
}
@Override
public void nodeUnclassifiedReadAccess(SNode node) {
SModel model = node.getModel();
if (model != null) {
if (model == myBuilder.currentInputModel) {
addNodeAccess(node.getContainingRoot());
} else if (model == myBuilder.currentOutputModel) {
addOutputNodeAccess(node.getContainingRoot());
} else if (model == myBuilder.originalInputModel) {
addOriginalNodeAccess(node.getContainingRoot());
} else {
addModelAccess(model);
}
}
}
@Override
public void modelNodesReadAccess(SModel model) {
if (model == myBuilder.currentInputModel || model == myBuilder.currentOutputModel || model == myBuilder.originalInputModel) {
dependsOnModelNodes = true;
} else {
addModelAccess(model);
}
}
@Nullable
public SNode getOriginalRoot() {
return myOriginalRoot;
}
public String getHash() {
return myHash;
}
public Collection<SNode> getDependsOn() {
return Collections.unmodifiableSet(dependsOn);
}
public Collection<SModel> getDependsOnModels() {
return Collections.unmodifiableSet(dependsOnModels);
}
public boolean isDependsOnConditionals() {
return dependsOnConditionals && myOriginalRoot != null;
}
public boolean isDependsOnModelNodes() {
return dependsOnModelNodes;
}
public boolean isUnchanged() {
return isUnchanged;
}
public void loadDependencies(GenerationRootDependencies previous) {
mySavedDependencies = previous;
isUnchanged = true;
}
public GenerationRootDependencies getSavedDependencies() {
return mySavedDependencies;
}
}