From 9ddf1fc12e29504295f961815ef46cea3550870c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20=C3=96qvist?= <jesper.oqvist@cs.lth.se> Date: Sun, 17 Jan 2016 15:07:48 +0100 Subject: [PATCH] Add collection attribute runtime debug check Added a runtime debug check for collection attributes, checking that a contribution contributes to a target node that is under a common collection root node with the source node. Removed target null check in collection attribute code - the target of a contribution should always be non null. see #251 (bitbucket) --- src/jastadd/ast/CollectionAttributes.jrag | 5 ++ src/jastadd/ast/JragCodeGen.jrag | 21 ++--- src/template/ast/Circular.tt | 2 +- src/template/ast/Collections.tt | 101 +++++++++++++--------- 4 files changed, 77 insertions(+), 52 deletions(-) diff --git a/src/jastadd/ast/CollectionAttributes.jrag b/src/jastadd/ast/CollectionAttributes.jrag index 306084c6..545f8719 100644 --- a/src/jastadd/ast/CollectionAttributes.jrag +++ b/src/jastadd/ast/CollectionAttributes.jrag @@ -36,8 +36,12 @@ aspect CollectionAttributes { eq CollDecl.isCollection() = true; + /** @return the type name of the collection root node */ syn String CollDecl.rootType() = root().name(); + /** @return the type name of the collection root node */ + syn String CollEq.rootType() = decl().rootType(); + /** @return the return type of the collection attribute */ syn String CollEq.getType() = decl().getType(); @@ -117,6 +121,7 @@ aspect CollectionAttributes { } syn TypeDecl AttrDecl.root() = grammar().root(); + eq CollDecl.root() = root != null ? grammar().lookup(root) : super.root(); // Only used by circular collection attributes. diff --git a/src/jastadd/ast/JragCodeGen.jrag b/src/jastadd/ast/JragCodeGen.jrag index 06c311ac..eaf12b6e 100644 --- a/src/jastadd/ast/JragCodeGen.jrag +++ b/src/jastadd/ast/JragCodeGen.jrag @@ -220,17 +220,16 @@ aspect JragCodeGen { if (config().lazyMaps()) { if (!isCircular()) { if (getNumParameter() != 0 && config().visitCheckEnabled() && config().rewriteEnabled()) { - sb.append("if (" + signature() + "_visited == null) " + signature() - + "_visited = " + config().createDefaultMap() + ";\n"); - } - else if (getNumParameter() != 0 && config().visitCheckEnabled()) { - sb.append("if (" + signature() + "_visited == null) " + signature() - + "_visited = " + config().createDefaultSet() + ";\n"); + sb.append(String.format("if (%s_visited == null) %s_visited = %s;\n", + signature(), signature(), config().createDefaultMap())); + } else if (getNumParameter() != 0 && config().visitCheckEnabled()) { + sb.append(String.format("if (%s_visited == null) %s_visited = %s;\n", + signature(), signature(), config().createDefaultSet())); } } if (getNumParameter() != 0 && (isLazy() || isCircular())) { - sb.append("if (" + signature() + "_values == null) " + signature() - + "_values = " + config().createDefaultMap() + ";\n"); + sb.append(String.format("if (%s_values == null) %s_values = %s;\n", + signature(), signature(), config().createDefaultMap())); } } return sb.toString(); @@ -257,7 +256,9 @@ aspect JragCodeGen { * @return {@code true} if the attribute is declared as NTA in the aspect file */ syn boolean AttrDecl.declaredNTA() = false; + eq SynDecl.declaredNTA() = getNTA(); + eq InhDecl.declaredNTA() = getNTA(); public static String ASTNode.boxedType(String type) { @@ -413,7 +414,7 @@ aspect JragCodeGen { public boolean TypeDecl.hasLazySynEqFor(AttrDecl attr) { if (attr instanceof SynDecl) { SynEq synEq = lookupSynEq(attr.signature()); - return synEq != null && (synEq.decl().isLazy() || synEq.decl().isCircular()) ; + return synEq != null && (synEq.decl().isLazy() || synEq.decl().isCircular()); } return false; } @@ -663,7 +664,7 @@ aspect JragCodeGen { + " was affected by a bug causing the equation value to be discarded! " + "(fixed since version 2.1.11)"); } - String attrName = getName().substring(3); // remove get + String attrName = getName().substring(3); if (comp.name().equals(attrName) && comp instanceof AggregateComponentNTA || attrName.equals(comp.name() + "Opt") && comp instanceof OptionalComponentNTA || attrName.equals(comp.name() + "List") && comp instanceof ListComponentNTA) { diff --git a/src/template/ast/Circular.tt b/src/template/ast/Circular.tt index 30c338cc..e51626b1 100644 --- a/src/template/ast/Circular.tt +++ b/src/template/ast/Circular.tt @@ -45,7 +45,7 @@ $if(#isCollection) while (_node != null && !(_node instanceof #rootType)) { _node = _node.getParent(); } - $include(collDebugCheck) + $include(CollDecl.collDebugCheck) #rootType root = (#rootType) _node; if (root.collecting_contributors_#collectionId) { throw new RuntimeException("Circularity during survey phase"); diff --git a/src/template/ast/Collections.tt b/src/template/ast/Collections.tt index df3cb9df..afb12743 100644 --- a/src/template/ast/Collections.tt +++ b/src/template/ast/Collections.tt @@ -25,11 +25,11 @@ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. -collDebugCheck [[ +CollDecl.collDebugCheck [[ $if(DebugMode) if (node == null) { throw new RuntimeException( - "Trying to evaluate collection attribute in subtree not attached to main tree"); + "Trying to evaluate collection attribute #getTarget.#getName() in subtree not attached to main tree."); } $endif ]] @@ -41,7 +41,7 @@ CollDecl.computeMethod:onePhase [[ while (node != null && !(node instanceof #rootType)) { node = node.getParent(); } - $include(collDebugCheck) + $include(CollDecl.collDebugCheck) #rootType root = (#rootType) node; root.survey_#collectionId(); if (#(signature)_value == null) { @@ -58,7 +58,7 @@ CollDecl.computeMethod:twoPhase [[ while (node != null && !(node instanceof #rootType)) { node = node.getParent(); } - $include(collDebugCheck) + $include(CollDecl.collDebugCheck) #rootType root = (#rootType) node; root.survey_#collectionId(); #getType _computedValue = $BottomValue; @@ -71,7 +71,7 @@ CollDecl.computeMethod:twoPhase [[ } ]] -CollEq.collectContributors:onePhase = [[ +CollEq.collectContributors:onePhase [[ // #declaredat $if(HasCondition) if (#getCondition) { @@ -85,13 +85,12 @@ $endif CollEq.contribution:onePhase [[ $if(#iterableTarget) for (#getTargetName target : (Iterable<? extends #getTargetName>) (#getReference)) { - if (target != null) { - if (target.#(signature)_value == null) { - target.#(signature)_value = $BottomValue; - } - #getType collection = target.#(signature)_value; - $include(CollEq.addValueToCollection) + $include(CollEq.targetDebugCheck) + if (target.#(signature)_value == null) { + target.#(signature)_value = $BottomValue; } + #getType collection = target.#(signature)_value; + $include(CollEq.addValueToCollection) } $else { @@ -103,19 +102,18 @@ $if(#implicitTarget) $include(CollEq.addValueToCollection) $else #getTargetName target = #getReference; - if (target != null) { - if (target.#(signature)_value == null) { - target.#(signature)_value = $BottomValue; - } - #getType collection = target.#(signature)_value; - $include(CollEq.addValueToCollection) + $include(CollEq.targetDebugCheck) + if (target.#(signature)_value == null) { + target.#(signature)_value = $BottomValue; } + #getType collection = target.#(signature)_value; + $include(CollEq.addValueToCollection) $endif } $endif ]] -CollEq.collectContributors:twoPhase = [[ +CollEq.collectContributors:twoPhase [[ // #declaredat $if(HasCondition) if (#getCondition) { @@ -129,41 +127,62 @@ $endif CollEq.contribution:twoPhase [[ $if(#iterableTarget) for (#getTargetName target : (Iterable<? extends #getTargetName>) (#getReference)) { - if (target != null) { - java.util.Set<$ASTNode> contributors = _map.get(target); - if (contributors == null) { - contributors = new java.util.HashSet<$ASTNode>(); - _map.put(($ASTNode) target, contributors); - } - contributors.add(this); + $include(CollEq.targetDebugCheck) + java.util.Set<$ASTNode> contributors = _map.get(target); + if (contributors == null) { + contributors = new java.util.HashSet<$ASTNode>(); + _map.put(($ASTNode) target, contributors); } + contributors.add(this); } $else { $if(#implicitTarget) - if (_root != null) { - java.util.Set<$ASTNode> contributors = _map.get(_root); - if (contributors == null) { - contributors = new java.util.HashSet<$ASTNode>(); - _map.put(($ASTNode) _root, contributors); - } - contributors.add(this); + java.util.Set<$ASTNode> contributors = _map.get(_root); + if (contributors == null) { + contributors = new java.util.HashSet<$ASTNode>(); + _map.put(($ASTNode) _root, contributors); } + contributors.add(this); $else #getTargetName target = (#getTargetName) (#getReference); - if (target != null) { - java.util.Set<$ASTNode> contributors = _map.get(target); - if (contributors == null) { - contributors = new java.util.HashSet<$ASTNode>(); - _map.put(($ASTNode) target, contributors); - } - contributors.add(this); + $include(CollEq.targetDebugCheck) + java.util.Set<$ASTNode> contributors = _map.get(target); + if (contributors == null) { + contributors = new java.util.HashSet<$ASTNode>(); + _map.put(($ASTNode) target, contributors); } + contributors.add(this); $endif } $endif ]] +CollEq.targetDebugCheck [[ +$if(DebugMode) +ASTNode _targetRoot = target; +ASTNode _targetParent = target; +while (_targetParent != null) { + _targetParent = _targetParent.getParent(); + if (_targetParent instanceof #rootType) { + _targetRoot = _targetParent; + } +} +ASTNode _sourceRoot = _root; +ASTNode _sourceParent = _root; +while (_sourceParent != null) { + _sourceParent = _sourceParent.getParent(); + if (_sourceParent instanceof #rootType) { + _sourceRoot = _sourceParent; + } +} +if (_targetRoot != _sourceRoot) { + throw new RuntimeException("Contribution source and target do not share a common collection " + + "root node for collection attribute #getTargetName.#getTargetAttributeName()."); +} +$endif +]] + CollDecl.collectContributors:header [[ $if(#onePhase) protected void collect_contributors_#collectionId(#rootType _root) { @@ -188,7 +207,7 @@ $endif } ]] -CollDecl.contributeTo:default = [[ +CollDecl.contributeTo:default [[ protected void contributeTo_#(signature)(#getType collection) { } ]] @@ -255,7 +274,7 @@ $endif } ]] -Collection.flush = [[ +Collection.flush [[ $if(#onePhase) collect_contributors_#collectionId = false; $else -- GitLab