blob: bd222ad71b02465c1864b897330874dfc0933582 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2019 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.internal.r.core.sourcemodel.RSourceElementByElementAccess.DocuCommentableElement;
import org.eclipse.statet.ltk.model.core.elements.IModelElement;
import org.eclipse.statet.ltk.model.core.elements.ISourceStructElement;
import org.eclipse.statet.r.core.model.IRLangSourceElement;
import org.eclipse.statet.r.core.model.IRModelInfo;
import org.eclipse.statet.r.core.model.RDocuLink;
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 IModelElement.Filter {
private IRoxygenAnalyzeContext context;
private List<RAstNode> comments;
private Iterator<RAstNode> commentsIterator;
private DocuComment nextComment;
private int nextCommentRefOffset;
public RoxygenAnalyzer() {
}
public void updateModel(final IRoxygenAnalyzeContext context) {
this.context= context;
final IRModelInfo 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 ISourceStructElement sourceElement= model.getSourceElement();
if (sourceElement instanceof IRLangSourceElement) {
include(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 IModelElement element) {
final IRLangSourceElement rElement= (IRLangSourceElement) element;
if (this.nextComment == null) {
return true;
}
final int offset= rElement.getSourceRange().getStartOffset();
while (this.nextCommentRefOffset < offset) {
checkElement(null);
nextDocuComment();
}
if (this.nextCommentRefOffset == offset) {
if (rElement instanceof DocuCommentableElement) {
final RDocuLink link= new RDocuLink(rElement, this.nextComment);
this.nextComment.addAttachment(link);
((DocuCommentableElement) rElement).setDocu(this.nextComment);
checkElement(rElement);
nextDocuComment();
}
}
if (this.nextCommentRefOffset < offset + rElement.getSourceRange().getLength()) {
return rElement.hasSourceChildren(this);
}
return false;
}
private void checkElement(final IRLangSourceElement 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);
}
}
}
}