diff --git a/core/org.eclipse.cdt.core.tests/resources/rewrite/CommentHandlingTestSource.rts b/core/org.eclipse.cdt.core.tests/resources/rewrite/CommentHandlingTestSource.rts index 422b99ae02b..c89f4945db9 100644 --- a/core/org.eclipse.cdt.core.tests/resources/rewrite/CommentHandlingTestSource.rts +++ b/core/org.eclipse.cdt.core.tests/resources/rewrite/CommentHandlingTestSource.rts @@ -2978,6 +2978,7 @@ class test //= =>leading +#ifndef TEST_H_ = //TEST =>trailing =>freestanding @@ -2999,6 +3000,9 @@ class test //= =>leading +#ifndef TEST_H_ = /* + * Licence information... + */ =>trailing =>freestanding @@ -3021,6 +3025,9 @@ class test //= =>leading +#ifndef TEST_H_ = /* + * Licence information... + */ class test { }; = //test @@ -3054,7 +3061,11 @@ private: //= =>leading +#ifndef HIDEMETHOD_H_ = /* + * HideMethod.h + */ =>trailing +#endif = /* HIDEMETHOD_H_ */ =>freestanding //!CommentRecognition Bug 233438 @@ -3077,6 +3088,7 @@ private: //= =>leading =>trailing +#endif = /* HIDEMETHOD_H_ */ =>freestanding //@test.cpp @@ -3122,6 +3134,7 @@ private: //= =>leading =>trailing +#endif = /* HIDEMETHOD_H_ */ =>freestanding //@test.cpp @@ -3145,4 +3158,44 @@ int HideMethod::methode2(){ =>trailing i++; = //comment =>freestanding +//!CommentRecognition preprocessor directives comment recognition +//#org.eclipse.cdt.core.parser.tests.rewrite.comenthandler.CommentHandlingTest +//@main.cpp +//c1 +int i;//c2 +//inc1 +//inc2 + +#include "foo.h" /*inc3*/ /*inc4*/ +//main +int main() { + return 0; + //block1 +} +//ifdef1 +#ifdef X //ifdef2 +//= +=>leading +int i; = //c1 +#include "foo.h" = //inc1 , //inc2 +int main() { + return 0; + //block1 +} = //main +#ifdef X = //ifdef1 +=>trailing +int i; = //c2 +#include "foo.h" = /*inc3*/ , /*inc4*/ +#ifdef X = //ifdef2 +=>freestanding +{ + return 0; + //block1 +} = //block1 +//@foo.h +void foo(); +//= +=>leading +=>trailing +=>freestanding \ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java index a7d748a3333..402fb71444f 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java @@ -12,9 +12,9 @@ package org.eclipse.cdt.internal.core.dom.rewrite.commenthandler; import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; +import java.util.Iterator; import java.util.List; -import java.util.TreeMap; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTArrayModifier; @@ -22,6 +22,7 @@ import org.eclipse.cdt.core.dom.ast.IASTComment; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTInitializer; @@ -33,15 +34,10 @@ import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; -import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; /** * This is the starting point of the entire comment handling process. The creation of the @@ -56,33 +52,40 @@ import org.eclipse.core.runtime.Path; */ public class ASTCommenter { - private static final class PPRangeChecker extends ASTVisitor { - int ppOffset; - int commentOffset; - boolean isPrePPComment = true; + private static final class PreprocessorRangeChecker extends ASTVisitor { + int statementOffset; + IASTFileLocation commentNodeLocation; + boolean isPreStatementComment = true; - private PPRangeChecker(boolean visitNodes, int nextPPOfset, int commentNodeOffset) { - super(visitNodes); - ppOffset = nextPPOfset; - commentOffset = commentNodeOffset; + private PreprocessorRangeChecker(int statementOffset, IASTFileLocation commentNodeLocation) { + super(true); + this.statementOffset = statementOffset; + this.commentNodeLocation = commentNodeLocation; } private int checkOffsets(IASTNode node) { int offset = ((ASTNode)node).getOffset(); - int status = ASTVisitor.PROCESS_CONTINUE; + int status = PROCESS_CONTINUE; - if (offset > commentOffset && offset < ppOffset) { - isPrePPComment = false; - status = ASTVisitor.PROCESS_ABORT; - } else if ((offset + ((ASTNode)node).getLength() < commentOffset)) { - status = ASTVisitor.PROCESS_SKIP; - } else if (offset > ppOffset) { - status = ASTVisitor.PROCESS_ABORT; + if (isCommentOnSameLine(node) + || offset > commentNodeLocation.getNodeOffset() + && offset < statementOffset) { + isPreStatementComment = false; + status = PROCESS_ABORT; + } else if ((offset + ((ASTNode) node).getLength() < commentNodeLocation.getNodeOffset())) { + status = PROCESS_SKIP; + } else if (offset > statementOffset) { + status = PROCESS_ABORT; } return status; } + private boolean isCommentOnSameLine(IASTNode node) { + return commentNodeLocation.getStartingLineNumber() == node.getFileLocation() + .getEndingLineNumber(); + } + @Override public int visit(ICPPASTBaseSpecifier baseSpecifier) { return checkOffsets(baseSpecifier); @@ -168,141 +171,115 @@ public class ASTCommenter { * Creates a NodeCommentMap for the given TranslationUnit. This is the only way * to get a NodeCommentMap which contains all the comments mapped against nodes. * - * @param transUnit TranslationUnit + * @param tu TranslationUnit * @return NodeCommentMap */ - public static NodeCommentMap getCommentedNodeMap(IASTTranslationUnit transUnit){ - if (transUnit == null) { - return new NodeCommentMap(); + public static NodeCommentMap getCommentedNodeMap(IASTTranslationUnit tu){ + NodeCommentMap commentMap = new NodeCommentMap(); + if (tu == null) { + return commentMap; } - List comments = removeNotNeededComments(transUnit); - if (comments == null || comments.isEmpty()) { - return new NodeCommentMap(); + IASTComment[] commentsArray = tu.getComments(); + if (commentsArray == null) { + return commentMap; } - return addCommentsToCommentMap(transUnit, comments); + // Note that constructing a real ArrayList is required here, since in filterNonTuComments, the + // remove-method will be invoked on the list's iterator. Calling it on the type Arrays$ArrayList (the + // resulting type of Arrays.asList() ) would throw a UnsupportedOperationException. + ArrayList comments = new ArrayList(Arrays.asList(commentsArray)); + filterNonTuComments(comments); + return addCommentsToCommentMap(tu, comments); } - private static List removeNotNeededComments(IASTTranslationUnit transUnit) { - List comments = getCommentsInWorkspace(transUnit); - if (comments == null || comments.isEmpty()) { - return null; + /** + * Note that passing an ArrayList (instead of just List or Collection) is required here, since this + * guarantees that the call to the remove-method on the list's iterator will not result in an + * UnsupportedOperationException which might be the case for other Collection/List types. + */ + private static void filterNonTuComments(ArrayList comments) { + Iterator iterator = comments.iterator(); + while (iterator.hasNext()) { + if (!iterator.next().isPartOfTranslationUnitFile()) { + iterator.remove(); + } } - return removeAllPreprocessorComments(transUnit, comments); } - private static List getCommentsInWorkspace(IASTTranslationUnit tu) { - IASTComment[] comments = tu.getComments(); - ArrayList commentsInWorkspace = new ArrayList(); - - if (comments == null || comments.length == 0) { - return null; - } - - for (IASTComment comment : comments) { - if (isInWorkspace(comment)) { - commentsInWorkspace.add(comment); - } - } - return commentsInWorkspace; - } - - private static List removeAllPreprocessorComments(IASTTranslationUnit tu, - List comments) { - IASTPreprocessorStatement[] preprocessorStatements = tu.getAllPreprocessorStatements(); - TreeMap treeOfPreProcessorLines = new TreeMap(); - TreeMap> ppOffsetForFiles = new TreeMap>(); - - for (IASTPreprocessorStatement statement : preprocessorStatements) { - if (isInWorkspace(statement)) { - String fileName = statement.getFileLocation().getFileName(); - treeOfPreProcessorLines.put(statement.getFileLocation().getStartingLineNumber(), fileName); - ArrayList offsetList = ppOffsetForFiles.get(fileName); - if (offsetList == null) { - offsetList = new ArrayList(); - ppOffsetForFiles.put(fileName, offsetList); - } - offsetList.add(((ASTNode)statement).getOffset()); - } - } - - ArrayList commentsInCode = new ArrayList(); - for (IASTComment comment : comments) { - IASTFileLocation commentFileLocation = comment.getFileLocation(); - int comStartLineNumber = commentFileLocation.getStartingLineNumber(); - String fileName = commentFileLocation.getFileName(); - if (treeOfPreProcessorLines.containsKey(comStartLineNumber) - && treeOfPreProcessorLines.get(comStartLineNumber).equals(fileName)) { - continue; - } - if (commentIsAtTheBeginningBeforePreprocessorStatements(comment, - ppOffsetForFiles.get(fileName), tu)) { - continue; - } - commentsInCode.add(comment); - } - return commentsInCode; - } - - private static boolean commentIsAtTheBeginningBeforePreprocessorStatements(IASTComment comment, - ArrayList listOfPreProcessorOffset, IASTTranslationUnit tu) { - if (listOfPreProcessorOffset == null) { - return false; - } - - if (comment.getTranslationUnit() == null || comment.getTranslationUnit().getDeclarations().length < 1) { + private static boolean isCommentDirectlyBeforePreprocessorStatement(IASTComment comment, + IASTPreprocessorStatement statement, IASTTranslationUnit tu) { + if (tu == null || tu.getDeclarations().length == 0) { return true; } - IASTDeclaration decl = comment.getTranslationUnit().getDeclarations()[0]; - String commentFileName = comment.getFileLocation().getFileName(); - boolean sameFile = decl.getFileLocation().getFileName().equals(commentFileName); - int commentNodeOffset = ((ASTNode)comment).getOffset(); - if (sameFile) { - if (decl.getFileLocation().getNodeOffset() < commentNodeOffset) { - return false; - } + IASTFileLocation commentLocation = comment.getFileLocation(); + int preprcessorOffset = statement.getFileLocation().getNodeOffset(); + if (preprcessorOffset > commentLocation.getNodeOffset()) { + PreprocessorRangeChecker vister = new PreprocessorRangeChecker(preprcessorOffset, commentLocation); + tu.accept(vister); + return vister.isPreStatementComment; } - Collections.sort(listOfPreProcessorOffset); - int nextPPOfset = -1; - for (Integer integer : listOfPreProcessorOffset) { - if (integer > commentNodeOffset) { - nextPPOfset = integer; - PPRangeChecker visti = new PPRangeChecker(true, nextPPOfset, commentNodeOffset); - tu.accept(visti); - if (visti.isPrePPComment) { - return true; - } - } - } - return false; } - private static boolean isInWorkspace(IASTNode node) { - IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); - IPath nodePath = new Path(node.getContainingFilename()); - for (IProject project : projects) { - if (project.getLocation().isPrefixOf(nodePath)) return true; - } - return false; + public static boolean isInWorkspace(IASTNode node) { + return node.isPartOfTranslationUnitFile(); } - private static NodeCommentMap addCommentsToCommentMap(IASTTranslationUnit rootNode, - List comments){ + private static NodeCommentMap addCommentsToCommentMap(IASTTranslationUnit tu, + ArrayList comments){ NodeCommentMap commentMap = new NodeCommentMap(); CommentHandler commHandler = new CommentHandler(comments); - IASTDeclaration[] declarations = rootNode.getDeclarations(); - for (int i = 0; i < declarations.length; i++) { - if (isInWorkspace(declarations[i])) { - ASTCommenterVisitor commenter = new ASTCommenterVisitor(commHandler, commentMap); - declarations[i].accept(commenter); - - // Add the remaining comments to the last declaration to prevent comment loss. - if (i == declarations.length - 1) { - commenter.addRemainingComments(declarations[i]); - } + assignPreprocessorComments(commentMap, comments, tu); + ASTCommenterVisitor commenter = new ASTCommenterVisitor(commHandler, commentMap); + tu.accept(commenter); + return commentMap; + } + + /** + * Note that passing an ArrayList (instead of just List or Collection) is required here, since this + * guarantees that the call to the remove-method on the list's iterator will not result in an + * UnsupportedOperationException which might be the case for other Collection/List types. + */ + private static void assignPreprocessorComments(NodeCommentMap commentMap, + ArrayList comments, IASTTranslationUnit tu) { + IASTPreprocessorStatement[] preprocessorStatementsArray = tu.getAllPreprocessorStatements(); + if (preprocessorStatementsArray == null) { + return; + } + List preprocessorStatements = Arrays.asList(preprocessorStatementsArray); + + if (preprocessorStatements.isEmpty() || comments.isEmpty()) { + return; + } + + Iterator statementsIter = preprocessorStatements.iterator(); + Iterator commentIter = comments.iterator(); + IASTPreprocessorStatement curStatement = getNextNodeInTu(statementsIter); + IASTComment curComment = getNextNodeInTu(commentIter); + while (curStatement != null && curComment != null) { + int statementLineNr = curStatement.getFileLocation().getStartingLineNumber(); + int commentLineNr = curComment.getFileLocation().getStartingLineNumber(); + if (commentLineNr == statementLineNr) { + commentMap.addTrailingCommentToNode(curStatement, curComment); + commentIter.remove(); + curComment = getNextNodeInTu(commentIter); + } else if (commentLineNr > statementLineNr) { + curStatement = getNextNodeInTu(statementsIter); + } else if (isCommentDirectlyBeforePreprocessorStatement(curComment, curStatement, tu)) { + commentMap.addLeadingCommentToNode(curStatement, curComment); + commentIter.remove(); + curComment = getNextNodeInTu(commentIter); + } else { + curComment = getNextNodeInTu(commentIter); } } - return commentMap; - } + } + + private static T getNextNodeInTu(Iterator iter) { + if (!iter.hasNext()) { + return null; + } + T next = iter.next(); + return next.isPartOfTranslationUnitFile() ? next : getNextNodeInTu(iter); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java index 9fbd6bbf19f..a8a97e9dbb8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java @@ -17,6 +17,7 @@ import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; +import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.IASTExpression; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTName; @@ -25,7 +26,6 @@ import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; -import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; @@ -43,6 +43,7 @@ public class ASTCommenterVisitor extends ASTVisitor { protected NodeCommentMap commentMap; private NodeCommenter nodeCommenter; + private IASTDeclaration lastDecl; { shouldVisitBaseSpecifiers = true; @@ -57,6 +58,7 @@ public class ASTCommenterVisitor extends ASTVisitor { shouldVisitStatements = true; shouldVisitTemplateParameters = true; shouldVisitTypeIds = true; + shouldVisitTranslationUnit = true; } public ASTCommenterVisitor(CommentHandler commHandler, NodeCommentMap commentMap) { @@ -69,10 +71,6 @@ public class ASTCommenterVisitor extends ASTVisitor { nodeCommenter = new NodeCommenter(this, commHandler, commentMap); } - public void addRemainingComments(IASTDeclaration declaration) { - nodeCommenter.appendRemainingComments(declaration); - } - @Override public int visit(IASTName name) { return nodeCommenter.appendComments((ASTNode) name); @@ -100,7 +98,10 @@ public class ASTCommenterVisitor extends ASTVisitor { @Override public int visit(IASTDeclaration declaration) { - return nodeCommenter.appendComments((ASTNode) declaration); + if (ASTCommenter.isInWorkspace(declaration)) { + return nodeCommenter.appendComments((ASTNode) declaration); + } + return PROCESS_SKIP; } @Override @@ -131,9 +132,13 @@ public class ASTCommenterVisitor extends ASTVisitor { @Override public int leave(IASTTranslationUnit tu) { nodeCommenter.appendComments((ASTNode) tu); + if (lastDecl != null) { + nodeCommenter.appendRemainingComments(lastDecl); + } return PROCESS_CONTINUE; } + @Override public int leave(IASTName name) { nodeCommenter.appendComments((ASTNode) name); @@ -142,6 +147,7 @@ public class ASTCommenterVisitor extends ASTVisitor { @Override public int leave(IASTDeclaration declaration) { + lastDecl = declaration; nodeCommenter.appendComments((ASTNode) declaration); return PROCESS_CONTINUE; } @@ -215,5 +221,5 @@ public class ASTCommenterVisitor extends ASTVisitor { public int leave( IASTComment comment){ nodeCommenter.appendComments((ASTNode) comment); return PROCESS_CONTINUE; - } + } }