All Downloads are FREE. Search and download functionalities are using the official Maven repository.

software.amazon.smithy.syntax.FixBadDocComments Maven / Gradle / Ivy

/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License").
 * You may not use this file except in compliance with the License.
 * A copy of the License is located at
 *
 *  http://aws.amazon.com/apache2.0
 *
 * or in the "license" file accompanying this file. This file 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 software.amazon.smithy.syntax;

import java.util.List;
import java.util.function.Function;
import software.amazon.smithy.model.loader.IdlToken;

/**
 * Rewrites invalid documentation comments that don't come directly before a shape or member to be a normal comment.
 *
 * 

TODO: This does not remove every possible invalid documentation comment (e.g., doc comments after traits). */ final class FixBadDocComments implements Function { @Override public TokenTree apply(TokenTree tree) { TreeCursor root = tree.zipper(); // These sections can never have doc comments. updateDirectChildren(root.getFirstChild(TreeType.WS)); updateNestedChildren(root.getFirstChild(TreeType.CONTROL_SECTION)); updateNestedChildren(root.getFirstChild(TreeType.METADATA_SECTION)); // These sections should always be present in every model. TreeCursor shapeSection = root.getFirstChild(TreeType.SHAPE_SECTION); if (shapeSection == null) { return tree; } TreeCursor useSection = shapeSection.getFirstChild(TreeType.USE_SECTION); if (useSection == null) { return tree; } // Remove doc comments from NAMESPACE_STATEMENT if there are use statements (that is, no way a doc comment // is applied to the next shape statement). if (!useSection.getTree().isEmpty()) { updateNestedChildren(shapeSection.getFirstChild(TreeType.NAMESPACE_STATEMENT)); // Remove doc comments from all but the last use statement. List useStatements = useSection.getChildrenByType(TreeType.USE_STATEMENT); for (int i = 0; i < useStatements.size() - 1; i++) { updateNestedChildren(useStatements.get(i)); } } // Doc comments are never allowed in NODE_VALUE values. for (TreeCursor cursor : shapeSection.findChildrenByType(TreeType.NODE_VALUE)) { updateNestedChildren(cursor); } // Doc comments are never allowed in TRAIT values. for (TreeCursor cursor : shapeSection.findChildrenByType(TreeType.TRAIT)) { updateNestedChildren(cursor); } // Doc comments should not appear in TRAIT_STATEMENTS. for (TreeCursor cursor : shapeSection.findChildrenByType(TreeType.TRAIT_STATEMENTS)) { updateNestedChildren(cursor); } // Fix doc comments that come before apply statements. TreeCursor shapeStatements = shapeSection.getFirstChild(TreeType.SHAPE_STATEMENTS); if (shapeStatements != null) { // Find BRs in shape statements and look at the next sibling. for (TreeCursor br : shapeStatements.getChildrenByType(TreeType.BR)) { TreeCursor nextSibling = br.getNextSibling(); if (nextSibling == null || nextSibling.getFirstChild(TreeType.APPLY_STATEMENT) != null) { updateNestedChildren(br); } } // Fix any trailing doc comments in shape bodies for (TreeCursor members : shapeStatements.findChildrenByType(TreeType.SHAPE_MEMBERS)) { TreeCursor closeBrace = members.getLastChild(); if (closeBrace != null) { TreeCursor possibleTrailingWs = closeBrace.getPreviousSibling(); if (possibleTrailingWs != null && possibleTrailingWs.getTree().getType() == TreeType.WS) { updateDirectChildren(possibleTrailingWs); } } } } return tree; } private void updateDirectChildren(TreeCursor container) { if (container != null) { updateChildren(container.getChildrenByType(TreeType.COMMENT)); } } private void updateNestedChildren(TreeCursor container) { if (container != null) { updateChildren(container.findChildrenByType(TreeType.COMMENT)); } } private void updateChildren(List children) { for (TreeCursor comment : children) { if (isDocComment(comment)) { updateComment(comment); } } } private boolean isDocComment(TreeCursor cursor) { return cursor.getTree() .tokens() .findFirst() .filter(token -> token.getIdlToken() == IdlToken.DOC_COMMENT) .isPresent(); } private void updateComment(TreeCursor cursor) { cursor.getTree().tokens().findFirst().ifPresent(token -> { CapturedToken updatedToken = token.toBuilder() // Trim the first "/" from the lexeme. Note that this does make the spans inaccurate. .lexeme(token.getLexeme().subSequence(1, token.getLexeme().length())) .build(); TokenTree updatedTree = TokenTree.of(TreeType.COMMENT); updatedTree.appendChild(TokenTree.of(updatedToken)); cursor.getParent().getTree().replaceChild(cursor.getTree(), updatedTree); }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy