org.apache.groovy.parser.antlr4.GroovydocManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of groovy Show documentation
Show all versions of groovy Show documentation
Groovy: A powerful, dynamic language for the JVM
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.groovy.parser.antlr4;
import groovy.lang.Groovydoc;
import groovy.lang.groovydoc.GroovydocHolder;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ASTNode;
import org.codehaus.groovy.ast.AnnotatedNode;
import org.codehaus.groovy.ast.AnnotationNode;
import org.codehaus.groovy.ast.ClassHelper;
import org.codehaus.groovy.ast.expr.ConstantExpression;
import java.util.List;
import java.util.regex.Pattern;
import static org.apache.groovy.parser.antlr4.util.StringUtils.matches;
import static org.codehaus.groovy.runtime.DefaultGroovyMethods.asBoolean;
/**
* A utilities for managing groovydoc, e.g.
* 1) extracting groovydoc from groovy AST;
* 2) TODO extracting tags from groovydoc;
* 3) attach groovydoc to AST node as metadata
*/
public class GroovydocManager {
public static final String DOC_COMMENT = GroovydocHolder.DOC_COMMENT; // keys for meta data
private static final String GROOVYDOC_PREFIX = "/**";
private static final String RUNTIME_GROOVYDOC_PREFIX = GROOVYDOC_PREFIX + "@";
private static final String VALUE = "value";
private static final Pattern SPACES_PATTERN = Pattern.compile("\\s+");
private final boolean groovydocEnabled, runtimeGroovydocEnabled;
public GroovydocManager(final boolean groovydocEnabled, final boolean runtimeGroovydocEnabled) {
this.groovydocEnabled = groovydocEnabled;
this.runtimeGroovydocEnabled = runtimeGroovydocEnabled;
}
/**
* Attach doc comment to member node as meta data
*
*/
public void handle(ASTNode node, GroovyParser.GroovyParserRuleContext ctx) {
if (!(groovydocEnabled || runtimeGroovydocEnabled)) {
return;
}
if (!asBoolean(node) || !asBoolean(ctx)) {
return;
}
String docCommentNodeText = this.findDocCommentByNode(ctx);
if (null == docCommentNodeText) {
return;
}
attachDocCommentAsMetaData(node, docCommentNodeText);
attachGroovydocAnnotation(node, docCommentNodeText);
}
/*
* Attach doc comment to member node as meta data
*/
private void attachDocCommentAsMetaData(ASTNode node, String docCommentNodeText) {
if (!groovydocEnabled) {
return;
}
if (!(node instanceof GroovydocHolder)) {
return;
}
node.putNodeMetaData(DOC_COMMENT, new groovy.lang.groovydoc.Groovydoc(docCommentNodeText, (GroovydocHolder) node));
}
/*
* Attach Groovydoc annotation to the target element
*/
private void attachGroovydocAnnotation(ASTNode node, String docCommentNodeText) {
if (!runtimeGroovydocEnabled) {
return;
}
if (!(node instanceof AnnotatedNode)) {
return;
}
if (!docCommentNodeText.startsWith(RUNTIME_GROOVYDOC_PREFIX)) {
return;
}
AnnotatedNode annotatedNode = (AnnotatedNode) node;
AnnotationNode annotationNode = new AnnotationNode(ClassHelper.make(Groovydoc.class));
annotationNode.addMember(VALUE, new ConstantExpression(docCommentNodeText));
annotatedNode.addAnnotation(annotationNode);
}
private String findDocCommentByNode(ParserRuleContext node) {
if (!asBoolean(node)) {
return null;
}
if (node instanceof GroovyParser.ClassBodyContext) {
return null;
}
ParserRuleContext parentContext = node.getParent();
if (!asBoolean(parentContext)) {
return null;
}
String docCommentNodeText = null;
boolean sameTypeNodeBefore = false;
for (ParseTree child : parentContext.children) {
if (node == child) {
// if no doc comment node found and no siblings of same type before the node,
// try to find doc comment node of its parent
if (!asBoolean((Object) docCommentNodeText) && !sameTypeNodeBefore) {
return findDocCommentByNode(parentContext);
}
return docCommentNodeText;
}
if (node.getClass() == child.getClass()) { // e.g. ClassBodyDeclarationContext == ClassBodyDeclarationContext
docCommentNodeText = null;
sameTypeNodeBefore = true;
continue;
}
if (!(child instanceof GroovyParser.NlsContext || child instanceof GroovyParser.SepContext)) {
continue;
}
// doc comments are treated as NL
List extends TerminalNode> nlList =
child instanceof GroovyParser.NlsContext
? ((GroovyParser.NlsContext) child).NL()
: ((GroovyParser.SepContext) child).NL();
int nlListSize = nlList.size();
if (0 == nlListSize) {
continue;
}
for (int i = nlListSize - 1; i >= 0; i--) {
String text = nlList.get(i).getText();
if (matches(text, SPACES_PATTERN)) {
continue;
}
if (text.startsWith(GROOVYDOC_PREFIX)) {
docCommentNodeText = text;
} else {
docCommentNodeText = null;
}
break;
}
}
throw new GroovyBugError("node can not be found: " + node.getText()); // The exception should never be thrown!
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy