| /*=============================================================================# |
| # Copyright (c) 2009, 2021 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.r.core.sourcemodel; |
| |
| import static org.eclipse.statet.ltk.ast.core.AstNode.NA_OFFSET; |
| |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.statet.jcommons.lang.NonNull; |
| import org.eclipse.statet.jcommons.lang.Nullable; |
| |
| import org.eclipse.statet.internal.r.core.sourcemodel.RSourceElementByElementAccess.DocuCommentableElement; |
| import org.eclipse.statet.ltk.model.core.element.LtkModelElementFilter; |
| import org.eclipse.statet.ltk.model.core.element.SourceStructElement; |
| import org.eclipse.statet.r.core.model.RDocuLink; |
| import org.eclipse.statet.r.core.model.RLangSourceElement; |
| import org.eclipse.statet.r.core.model.RSourceUnitModelInfo; |
| import org.eclipse.statet.r.core.rsource.ast.DocuComment; |
| import org.eclipse.statet.r.core.rsource.ast.DocuTag; |
| import org.eclipse.statet.r.core.rsource.ast.NodeType; |
| import org.eclipse.statet.r.core.rsource.ast.RAstNode; |
| import org.eclipse.statet.r.core.rsource.ast.SourceComponent; |
| |
| |
| public class RoxygenAnalyzer implements LtkModelElementFilter<RLangSourceElement> { |
| |
| |
| private RoxygenAnalyzeContext context; |
| |
| private List<RAstNode> comments; |
| |
| private Iterator<RAstNode> commentsIterator; |
| private DocuComment nextComment; |
| private int nextCommentRefOffset; |
| |
| |
| public RoxygenAnalyzer() { |
| } |
| |
| |
| public void updateModel(final RoxygenAnalyzeContext context) { |
| this.context= context; |
| final RSourceUnitModelInfo model= context.getModelInfo(); |
| this.comments= ((SourceComponent) model.getAst().getRoot()).getComments(); |
| if (this.comments == null || this.comments.isEmpty()) { |
| return; |
| } |
| this.commentsIterator= this.comments.iterator(); |
| if (!nextDocuComment()) { |
| return; |
| } |
| final SourceStructElement<?, ?> sourceElement= model.getSourceElement(); |
| if (sourceElement instanceof RLangSourceElement) { |
| include((RLangSourceElement)sourceElement); |
| } |
| if (this.nextComment != null) { |
| checkElement(null); |
| } |
| } |
| |
| private boolean nextDocuComment() { |
| while (this.commentsIterator.hasNext()) { |
| final RAstNode next= this.commentsIterator.next(); |
| if (next.getNodeType() == NodeType.DOCU_AGGREGATION) { |
| this.nextComment= (DocuComment)next; |
| this.nextCommentRefOffset= this.nextComment.getSubsequentNodeOffset(); |
| if (this.nextCommentRefOffset != NA_OFFSET) { |
| return true; |
| } |
| else { |
| checkElement(null); |
| } |
| } |
| } |
| this.nextComment= null; |
| this.nextCommentRefOffset= Integer.MAX_VALUE; |
| return false; |
| } |
| |
| |
| @Override |
| public boolean include(final @NonNull RLangSourceElement element) { |
| if (this.nextComment == null) { |
| return true; |
| } |
| final int offset= element.getSourceRange().getStartOffset(); |
| while (this.nextCommentRefOffset < offset) { |
| checkElement(null); |
| nextDocuComment(); |
| } |
| if (this.nextCommentRefOffset == offset) { |
| if (element instanceof DocuCommentableElement) { |
| final RDocuLink link= new RDocuLink(element, this.nextComment); |
| this.nextComment.addAttachment(link); |
| ((DocuCommentableElement) element).setDocu(this.nextComment); |
| checkElement(element); |
| nextDocuComment(); |
| } |
| } |
| |
| if (this.nextCommentRefOffset < offset + element.getSourceRange().getLength()) { |
| return element.hasSourceChildren(this); |
| } |
| return false; |
| } |
| |
| private void checkElement(final @Nullable RLangSourceElement element) { |
| final List<DocuTag> tags= this.nextComment.getTags(); |
| for (final DocuTag tag : tags) { |
| final RoxygenTagType tagType= RoxygenTagType.TYPES.get(tag.getText()); |
| if (tagType != null) { |
| tagType.analyze(this.context, tag, element); |
| } |
| } |
| } |
| |
| } |