/* * Copyright (c) 2012, 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.engine.ast; import com.google.dart.engine.scanner.Token; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * The abstract class {@code AnnotatedNode} defines the behavior of nodes that can be annotated with * both a comment and metadata. * * @coverage dart.engine.ast */ public abstract class AnnotatedNode extends AstNode { /** * The documentation comment associated with this node, or {@code null} if this node does not have * a documentation comment associated with it. */ private Comment comment; /** * The annotations associated with this node. */ private NodeList<Annotation> metadata = new NodeList<Annotation>(this); /** * Initialize a newly created node. * * @param comment the documentation comment associated with this node * @param metadata the annotations associated with this node */ public AnnotatedNode(Comment comment, List<Annotation> metadata) { this.comment = becomeParentOf(comment); this.metadata.addAll(metadata); } @Override public final Token getBeginToken() { if (comment == null) { if (metadata.isEmpty()) { return getFirstTokenAfterCommentAndMetadata(); } else { return metadata.getBeginToken(); } } else if (metadata.isEmpty()) { return comment.getBeginToken(); } Token commentToken = comment.getBeginToken(); Token metadataToken = metadata.getBeginToken(); if (commentToken.getOffset() < metadataToken.getOffset()) { return commentToken; } return metadataToken; } /** * Return the documentation comment associated with this node, or {@code null} if this node does * not have a documentation comment associated with it. * * @return the documentation comment associated with this node */ public Comment getDocumentationComment() { return comment; } /** * Return the annotations associated with this node. * * @return the annotations associated with this node */ public NodeList<Annotation> getMetadata() { return metadata; } /** * Set the documentation comment associated with this node to the given comment. * * @param comment the documentation comment to be associated with this node */ public void setDocumentationComment(Comment comment) { this.comment = becomeParentOf(comment); } /** * Set the metadata associated with this node to the given metadata. * * @param metadata the metadata to be associated with this node */ public void setMetadata(List<Annotation> metadata) { this.metadata.clear(); this.metadata.addAll(metadata); } @Override public void visitChildren(AstVisitor<?> visitor) { if (commentIsBeforeAnnotations()) { safelyVisitChild(comment, visitor); metadata.accept(visitor); } else { for (AstNode child : getSortedCommentAndAnnotations()) { child.accept(visitor); } } } /** * Return the first token following the comment and metadata. * * @return the first token following the comment and metadata */ protected abstract Token getFirstTokenAfterCommentAndMetadata(); /** * Return {@code true} if the comment is lexically before any annotations. * * @return {@code true} if the comment is lexically before any annotations */ private boolean commentIsBeforeAnnotations() { if (comment == null || metadata.isEmpty()) { return true; } Annotation firstAnnotation = metadata.get(0); return comment.getOffset() < firstAnnotation.getOffset(); } /** * Return an array containing the comment and annotations associated with this node, sorted in * lexical order. * * @return the comment and annotations associated with this node in the order in which they * appeared in the original source */ private AstNode[] getSortedCommentAndAnnotations() { ArrayList<AstNode> childList = new ArrayList<AstNode>(); childList.add(comment); childList.addAll(metadata); AstNode[] children = childList.toArray(new AstNode[childList.size()]); Arrays.sort(children, AstNode.LEXICAL_ORDER); return children; } }