Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey Prigogin2011-12-14 03:44:22 +0000
committerSergey Prigogin2011-12-14 03:46:10 +0000
commitc521604dd1dde08dfd55e8e08fae1de4ad6a2e21 (patch)
treec222b9837b561e15d15f9ffc8386058a2d515f31 /core/org.eclipse.cdt.core/parser/org/eclipse
parent18ec28be0f857e0e6b6e7ee293b148f8dc64f21c (diff)
downloadorg.eclipse.cdt-c521604dd1dde08dfd55e8e08fae1de4ad6a2e21.tar.gz
org.eclipse.cdt-c521604dd1dde08dfd55e8e08fae1de4ad6a2e21.tar.xz
org.eclipse.cdt-c521604dd1dde08dfd55e8e08fae1de4ad6a2e21.zip
Bug 363244 - Generate Getters and Setters expands macro with typedef and
breaks formatting. The bug was fixed by minimizing areas of code affected by the refactoring changes. This minimization had a huge ripple effect.
Diffstat (limited to 'core/org.eclipse.cdt.core/parser/org/eclipse')
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTModificationMap.java12
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriter.java49
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriterVisitor.java41
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java2
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java11
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java8
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/InitializerWriter.java4
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java14
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/Scribe.java46
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java10
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ASTModificationHelper.java14
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGenerator.java1241
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGeneratorWriterVisitor.java45
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenter.java28
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/ASTCommenterVisitor.java18
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/CommentHandler.java11
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommentMap.java105
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java34
18 files changed, 1003 insertions, 690 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTModificationMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTModificationMap.java
index ea35926d435..ee28e24cea8 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTModificationMap.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/ASTModificationMap.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2007, 2008 Wind River Systems, Inc. and others.
+ * Copyright (c) 2007, 2011 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
@@ -7,6 +7,7 @@
*
* Contributors:
* Markus Schorn - initial API and implementation
+ * Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite;
@@ -15,6 +16,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification.ModificationKind;
@@ -22,20 +24,18 @@ import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification.ModificationKin
/**
* Represents a list of modifications to an AST node. If there are nested modifications
* to nodes introduced by insertions or replacements, these modifications are collected
- * in separate modification maps. I.e. a modification map represents one level of
- * modifications.
+ * in separate modification maps. I.e. a modification map represents one level of modifications.
* @see ASTModificationStore
* @since 5.0
*/
public class ASTModificationMap {
- private HashMap<IASTNode, List<ASTModification>> fModifications= new HashMap<IASTNode, List<ASTModification>>();
+ private final Map<IASTNode, List<ASTModification>> fModifications= new HashMap<IASTNode, List<ASTModification>>();
/**
* Adds a modification to this modification map.
*/
public void addModification(ASTModification mod) {
- final IASTNode targetNode = mod.getKind() == ASTModification.ModificationKind.INSERT_BEFORE ?
- mod.getTargetNode().getParent() : mod.getTargetNode();
+ IASTNode targetNode = mod.getTargetNode();
List<ASTModification> mods= fModifications.get(targetNode);
if (mods == null || mods.isEmpty()) {
mods= new ArrayList<ASTModification>();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriter.java
index 5b7229e5de9..dc19453bfbc 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriter.java
@@ -14,9 +14,13 @@ package org.eclipse.cdt.internal.core.dom.rewrite.astwriter;
import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
+import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
+import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
@@ -34,7 +38,6 @@ import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
*/
public class ASTWriter {
private ASTModificationStore modificationStore = new ASTModificationStore();
- private String givenIndentation = ""; //$NON-NLS-1$
/**
* Creates a <code>ASTWriter</code>.
@@ -44,16 +47,6 @@ public class ASTWriter {
}
/**
- * Creates a <code>ASTWriter</code> that indents the code.
- *
- * @param givenIndentation The indentation added to each line
- */
- public ASTWriter(String givenIndentation) {
- super();
- this.givenIndentation = givenIndentation;
- }
-
- /**
* Generates the source code representing this node.
*
* @param rootNode Node to write.
@@ -75,10 +68,9 @@ public class ASTWriter {
*
* @see ASTCommenter#getCommentedNodeMap(org.eclipse.cdt.core.dom.ast.IASTTranslationUnit)
*/
- public String write(IASTNode rootNode, NodeCommentMap commentMap)
- throws ProblemRuntimeException {
+ public String write(IASTNode rootNode, NodeCommentMap commentMap) throws ProblemRuntimeException {
ChangeGeneratorWriterVisitor writer = new ChangeGeneratorWriterVisitor(
- modificationStore, givenIndentation, null, commentMap);
+ modificationStore, null, commentMap);
if (rootNode != null) {
rootNode.accept(writer);
}
@@ -152,10 +144,35 @@ public class ASTWriter {
* @return <code>true</code> if the blank line between the nodes is needed.
*/
public static boolean requireBlankLineInBetween(IASTNode node1, IASTNode node2) {
- if (requiresTrailingBlankLine(node1))
+ if (node1 instanceof ICPPASTVisibilityLabel && node2 instanceof ICPPASTVisibilityLabel) {
+ return true;
+ }
+ if (suppressesTrailingBlankLine(node1)) {
+ return false;
+ }
+ if (node1 instanceof IASTPreprocessorIncludeStatement !=
+ node2 instanceof IASTPreprocessorIncludeStatement) {
+ return true;
+ }
+ if (isFunctionDeclaration(node1) != isFunctionDeclaration(node2)) {
+ return true;
+ }
+ if (requiresTrailingBlankLine(node1)) {
return true;
+ }
+
+ return requiresLeadingBlankLine(node2);
+ }
- return !suppressesTrailingBlankLine(node1) && requiresLeadingBlankLine(node2);
+ private static boolean isFunctionDeclaration(IASTNode node) {
+ if (!(node instanceof IASTSimpleDeclaration)) {
+ return false;
+ }
+ for (IASTDeclarator declarator : ((IASTSimpleDeclaration) node).getDeclarators()) {
+ if (declarator instanceof IASTFunctionDeclarator)
+ return true;
+ }
+ return false;
}
/**
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriterVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriterVisitor.java
index 16f9325785f..4ff5321d55a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriterVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/ASTWriterVisitor.java
@@ -13,7 +13,7 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.astwriter;
-import java.util.ArrayList;
+import java.util.List;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
@@ -29,6 +29,7 @@ import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTNodeLocation;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
@@ -62,28 +63,25 @@ public class ASTWriterVisitor extends ASTVisitor {
private boolean spaceNeededBeforeName;
{
- shouldVisitExpressions = true;
- shouldVisitStatements = true;
- shouldVisitNames = true;
+ shouldVisitArrayModifiers = true;
+ shouldVisitBaseSpecifiers = true;
shouldVisitDeclarations = true;
- shouldVisitDeclSpecifiers = true;
shouldVisitDeclarators = true;
- shouldVisitArrayModifiers= true;
+ shouldVisitDeclSpecifiers = true;
+ shouldVisitExpressions = true;
shouldVisitInitializers = true;
- shouldVisitBaseSpecifiers = true;
+ shouldVisitNames = true;
shouldVisitNamespaces = true;
- shouldVisitTemplateParameters = true;
shouldVisitParameterDeclarations = true;
+ shouldVisitPointerOperators = true;
+ shouldVisitStatements = true;
+ shouldVisitTemplateParameters = true;
shouldVisitTranslationUnit = true;
+ shouldVisitTypeIds = true;
}
public ASTWriterVisitor(NodeCommentMap commentMap) {
- this("", commentMap); //$NON-NLS-1$
- }
-
- public ASTWriterVisitor(String givenIndentation, NodeCommentMap commentMap) {
super();
- scribe.setGivenIndentation(givenIndentation);
init(commentMap);
this.commentMap = commentMap;
this.suppressLeadingBlankLine = true;
@@ -123,8 +121,8 @@ public class ASTWriterVisitor extends ASTVisitor {
}
}
- private ArrayList<IASTComment> getLeadingComments(IASTNode node) {
- ArrayList<IASTComment> leadingComments = commentMap.getLeadingCommentsForNode(node);
+ private List<IASTComment> getLeadingComments(IASTNode node) {
+ List<IASTComment> leadingComments = commentMap.getLeadingCommentsForNode(node);
IASTNodeLocation[] locs = node.getNodeLocations();
if (locs != null && locs.length > 0 && locs[0] instanceof IASTCopyLocation) {
IASTCopyLocation copyLoc = (IASTCopyLocation) locs[0];
@@ -240,6 +238,15 @@ public class ASTWriterVisitor extends ASTVisitor {
return ASTVisitor.PROCESS_SKIP;
}
+ @Override
+ public int visit(IASTPointerOperator pointerOperator) {
+ writeLeadingComments(pointerOperator);
+ if (!macroHandler.checkisMacroExpansionNode(pointerOperator)) {
+ declaratorWriter.writePointerOperator(pointerOperator);
+ }
+ return ASTVisitor.PROCESS_SKIP;
+ }
+
protected IASTName getParameterName(IASTDeclarator declarator) {
return declarator.getName();
}
@@ -303,6 +310,10 @@ public class ASTWriterVisitor extends ASTVisitor {
this.spaceNeededBeforeName = value;
}
+ public Scribe getScribe() {
+ return scribe;
+ }
+
public void newLine() {
scribe.newLine();
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java
index ba7fb2e8623..66d25dd9378 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclSpecWriter.java
@@ -267,7 +267,7 @@ public class DeclSpecWriter extends NodeWriter {
}
if (hasFreestandingComments(compDeclSpec)) {
- writeFreeStandingComments(compDeclSpec);
+ writeFreestandingComments(compDeclSpec);
}
scribe.decrementIndentationLevel();
scribe.print('}');
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
index 41ed66fc643..29e21800a75 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclarationWriter.java
@@ -98,17 +98,12 @@ public class DeclarationWriter extends NodeWriter {
writeVisibilityLabel((ICPPASTVisibilityLabel) declaration);
}
- if (hasTrailingComments(declaration)) {
- writeTrailingComments(declaration, false);
- }
- if (addNewLine) {
- scribe.newLine();
- }
+ writeTrailingComments(declaration, addNewLine);
if (hasFreestandingComments(declaration)) {
if (declaration instanceof IASTFunctionDefinition) {
scribe.newLine();
}
- writeFreeStandingComments(declaration);
+ writeFreestandingComments(declaration);
}
}
@@ -186,7 +181,7 @@ public class DeclarationWriter extends NodeWriter {
scribe.newLine(2);
writeDeclarationsInNamespace(namespaceDefinition, namespaceDefinition.getDeclarations());
if (hasFreestandingComments(namespaceDefinition)) {
- writeFreeStandingComments(namespaceDefinition);
+ writeFreestandingComments(namespaceDefinition);
}
scribe.newLine();
scribe.print('}');
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
index 4a9a8af3852..7d3fdf05c10 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/DeclaratorWriter.java
@@ -62,9 +62,7 @@ public class DeclaratorWriter extends NodeWriter {
}
visitor.setSpaceNeededBeforeName(false);
- if (hasTrailingComments(declarator)) {
- writeTrailingComments(declarator, false);
- }
+ writeTrailingComments(declarator, false);
}
protected void writeDefaultDeclarator(IASTDeclarator declarator) {
@@ -81,7 +79,7 @@ public class DeclaratorWriter extends NodeWriter {
protected void writePointerOperators(IASTDeclarator declarator, IASTPointerOperator[] pointOps) {
for (IASTPointerOperator operator : pointOps) {
- writePointerOp(operator);
+ writePointerOperator(operator);
}
}
@@ -194,7 +192,7 @@ public class DeclaratorWriter extends NodeWriter {
}
}
- private void writePointerOp(IASTPointerOperator operator) {
+ public void writePointerOperator(IASTPointerOperator operator) {
if (operator instanceof IASTPointer) {
IASTPointer pointOp = (IASTPointer) operator;
writePointer(pointOp);
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/InitializerWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/InitializerWriter.java
index 7adc8fdce86..8b1da40bc37 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/InitializerWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/InitializerWriter.java
@@ -51,8 +51,8 @@ public class InitializerWriter extends NodeWriter{
} else if (initializer instanceof ICPPASTConstructorChainInitializer) {
writeConstructorChainInitializer((ICPPASTConstructorChainInitializer) initializer);
}
- if (hasTrailingComments(initializer))
- writeTrailingComments(initializer, false);
+
+ writeTrailingComments(initializer, false);
}
private void writeEqualsInitializer(IASTEqualsInitializer initializer) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
index 627e8158a5f..aa160a77bdf 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/NodeWriter.java
@@ -11,7 +11,7 @@
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.astwriter;
-import java.util.ArrayList;
+import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTCopyLocation;
@@ -83,7 +83,7 @@ public class NodeWriter {
}
protected void writeTrailingComments(IASTNode node) {
- // Default is to write a new line after trailing comments.
+ // Default is to write a new line after the trailing comments.
writeTrailingComments(node, true);
}
@@ -106,8 +106,8 @@ public class NodeWriter {
return !getTrailingComments(node).isEmpty();
}
- private ArrayList<IASTComment> getTrailingComments(IASTNode node) {
- ArrayList<IASTComment> trailingComments = commentMap.getTrailingCommentsForNode(node);
+ private List<IASTComment> getTrailingComments(IASTNode node) {
+ List<IASTComment> trailingComments = commentMap.getTrailingCommentsForNode(node);
IASTNodeLocation[] locs = node.getNodeLocations();
if (locs != null && locs.length > 0 && locs[0] instanceof IASTCopyLocation) {
IASTCopyLocation loc = (IASTCopyLocation) locs[0];
@@ -120,8 +120,8 @@ public class NodeWriter {
return !getFreestandingComments(node).isEmpty();
}
- private ArrayList<IASTComment> getFreestandingComments(IASTNode node) {
- ArrayList<IASTComment> freestandingComments = commentMap.getFreestandingCommentsForNode(node);
+ private List<IASTComment> getFreestandingComments(IASTNode node) {
+ List<IASTComment> freestandingComments = commentMap.getFreestandingCommentsForNode(node);
IASTNodeLocation[] locs = node.getNodeLocations();
if (locs != null && locs.length > 0 && locs[0] instanceof IASTCopyLocation) {
IASTCopyLocation loc = (IASTCopyLocation) locs[0];
@@ -130,7 +130,7 @@ public class NodeWriter {
return freestandingComments;
}
- protected void writeFreeStandingComments(IASTNode node) {
+ protected void writeFreestandingComments(IASTNode node) {
for (IASTComment comment : getFreestandingComments(node)) {
scribe.print(comment.getComment());
scribe.newLine();
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/Scribe.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/Scribe.java
index 8bc32d8396d..7f715f5e28f 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/Scribe.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/Scribe.java
@@ -8,6 +8,7 @@
*
* Contributors:
* Institute for Software - initial API and implementation
+ * Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.astwriter;
@@ -19,42 +20,43 @@ package org.eclipse.cdt.internal.core.dom.rewrite.astwriter;
* @author Emanuel Graf IFS
*/
public class Scribe {
- private int indentationLevel = 0;
- // Any positive indentation size is good enough since the code is going to be formatted anyway.
- private int indentationSize = 4;
+ // Indentation is not necessary since the code is going to be formatted anyway.
+ // Preserved because some tests depend on it.
+ private static final int INDENTATION_SIZE = 4;
+ private final String newLine = System.getProperty("line.separator"); //$NON-NLS-1$
private StringBuilder buffer = new StringBuilder();
- private boolean isAtLineBeginning = true;
- private String newLine = System.getProperty("line.separator"); //$NON-NLS-1$
- private String givenIndentation;
+ private int indentationLevel = 0;
+ private boolean isAtBeginningOfLine = true;
private boolean skipLineBreaks;
private boolean skipSemicolons;
+ public String getLineSeparator() {
+ return newLine;
+ }
+
public void newLine() {
if (!skipLineBreaks) {
- isAtLineBeginning = true;
- buffer.append(getNewline());
+ isAtBeginningOfLine = true;
+ buffer.append(newLine);
}
}
+ public boolean isAtBeginningOfLine() {
+ return isAtBeginningOfLine;
+ }
+
private void indent() {
- if (givenIndentation != null) {
- buffer.append(givenIndentation);
- }
- printSpaces(indentationLevel * indentationSize);
+ printSpaces(indentationLevel * INDENTATION_SIZE);
}
private void indentIfNewLine() {
- if (isAtLineBeginning) {
- isAtLineBeginning = false;
+ if (isAtBeginningOfLine) {
+ isAtBeginningOfLine = false;
indent();
}
}
- private String getNewline() {
- return newLine;
- }
-
public void print(String code) {
indentIfNewLine();
buffer.append(code);
@@ -171,14 +173,6 @@ public class Scribe {
buffer.append(' ');
}
- public String getGivenIndentation() {
- return givenIndentation;
- }
-
- public void setGivenIndentation(String givenIndentation) {
- this.givenIndentation = givenIndentation;
- }
-
public void cleanCache() {
buffer = new StringBuilder();
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java
index ac8c6f21f37..fd0cf9a59a7 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/astwriter/StatementWriter.java
@@ -154,12 +154,8 @@ public class StatementWriter extends NodeWriter {
throw new ProblemRuntimeException((IASTProblemStatement)statement);
}
- if (hasTrailingComments(statement)) {
- writeTrailingComments(statement, newLine);
- } else if (newLine) {
- scribe.newLine();
- }
-
+ writeTrailingComments(statement, newLine);
+
return ASTVisitor.PROCESS_SKIP;
}
@@ -389,7 +385,7 @@ public class StatementWriter extends NodeWriter {
}
if (hasFreestandingComments(compoundStatement)) {
- writeFreeStandingComments(compoundStatement);
+ writeFreestandingComments(compoundStatement);
}
if (decrementIndentationLevelOneMore) {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ASTModificationHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ASTModificationHelper.java
index 3354844d4d1..30fd72f613a 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ASTModificationHelper.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ASTModificationHelper.java
@@ -15,8 +15,8 @@ import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
@@ -100,29 +100,29 @@ public class ASTModificationHelper {
private void copyComments(IASTNode newNode, IASTNode oldNode, NodeCommentMap commentMap) {
// Attach all the comments that is attached to oldNode to newNode
- ArrayList<IASTComment> leadingComments = commentMap.getLeadingCommentsForNode(oldNode);
+ List<IASTComment> leadingComments = commentMap.getLeadingCommentsForNode(oldNode);
for (IASTComment comment : leadingComments) {
commentMap.addLeadingCommentToNode(newNode, comment);
}
- ArrayList<IASTComment> trailingComments = commentMap.getTrailingCommentsForNode(oldNode);
+ List<IASTComment> trailingComments = commentMap.getTrailingCommentsForNode(oldNode);
for (IASTComment comment : trailingComments) {
commentMap.addTrailingCommentToNode(newNode, comment);
}
- ArrayList<IASTComment> freestandingComments = commentMap.getFreestandingCommentsForNode(oldNode);
+ List<IASTComment> freestandingComments = commentMap.getFreestandingCommentsForNode(oldNode);
for (IASTComment comment : freestandingComments) {
commentMap.addFreestandingCommentToNode(newNode, comment);
}
// Detach comments from oldNode (to avoid memory leak)
- HashMap<IASTNode, ArrayList<IASTComment>> leadingMap = commentMap.getLeadingMap();
+ Map<IASTNode, List<IASTComment>> leadingMap = commentMap.getLeadingMap();
leadingMap.remove(oldNode);
- HashMap<IASTNode, ArrayList<IASTComment>> trailingMap = commentMap.getTrailingMap();
+ Map<IASTNode, List<IASTComment>> trailingMap = commentMap.getTrailingMap();
trailingMap.remove(oldNode);
- HashMap<IASTNode, ArrayList<IASTComment>> freestandingMap = commentMap.getFreestandingMap();
+ Map<IASTNode, List<IASTComment>> freestandingMap = commentMap.getFreestandingMap();
freestandingMap.remove(oldNode);
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGenerator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGenerator.java
index d8d2b173c00..a42d26721ba 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGenerator.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGenerator.java
@@ -15,9 +15,13 @@ package org.eclipse.cdt.internal.core.dom.rewrite.changegenerator;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.TreeMap;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.ToolFactory;
@@ -30,15 +34,27 @@ 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.IASTExpression;
+import org.eclipse.cdt.core.dom.ast.IASTExpressionList;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
+import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
+import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
+import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
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.cpp.ICPPASTCatchHandler;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionWithTryBlock;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
import org.eclipse.cdt.core.formatter.CodeFormatter;
+import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification;
import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification.ModificationKind;
@@ -61,11 +77,11 @@ import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
+import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.TextUtilities;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
-import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
@@ -74,28 +90,31 @@ import org.eclipse.text.edits.TextEdit;
import org.eclipse.text.edits.TextEditGroup;
public class ChangeGenerator extends ASTVisitor {
- private final LinkedHashMap<String, Integer> sourceOffsets = new LinkedHashMap<String, Integer>();
- public LinkedHashMap<IASTNode, List<ASTModification>> modificationParent = new LinkedHashMap<IASTNode, List<ASTModification>>();
- private final LinkedHashMap<IFile, MultiTextEdit> changes = new LinkedHashMap<IFile, MultiTextEdit>();
+ private final Map<String, Integer> sourceOffsets = new LinkedHashMap<String, Integer>();
+ private final Map<IASTNode, Map<ModificationKind, List<ASTModification>>> classifiedModifications =
+ new HashMap<IASTNode, Map<ModificationKind, List<ASTModification>>>();
+ private final Map<IFile, MultiTextEdit> changes = new LinkedHashMap<IFile, MultiTextEdit>();
private CompositeChange change;
private final ASTModificationStore modificationStore;
private NodeCommentMap commentMap;
{
- shouldVisitExpressions = true;
- shouldVisitStatements = true;
+ shouldVisitArrayModifiers= true;
+ shouldVisitBaseSpecifiers = true;
shouldVisitNames = true;
shouldVisitDeclarations = true;
- shouldVisitDeclSpecifiers = true;
shouldVisitDeclarators = true;
- shouldVisitArrayModifiers= true;
+ shouldVisitDeclSpecifiers = true;
+ shouldVisitExpressions = true;
shouldVisitInitializers = true;
- shouldVisitBaseSpecifiers = true;
shouldVisitNamespaces = true;
- shouldVisitTemplateParameters = true;
shouldVisitParameterDeclarations = true;
+ shouldVisitPointerOperators = true;
+ shouldVisitStatements = true;
+ shouldVisitTemplateParameters = true;
shouldVisitTranslationUnit = true;
+ shouldVisitTypeIds = true;
}
public ChangeGenerator(ASTModificationStore modificationStore, NodeCommentMap commentMap) {
@@ -110,7 +129,7 @@ public class ChangeGenerator extends ASTVisitor {
public void generateChange(IASTNode rootNode, ASTVisitor pathProvider)
throws ProblemRuntimeException {
change = new CompositeChange(Messages.ChangeGenerator_compositeChange);
- initParentModList();
+ classifyModifications();
rootNode.accept(pathProvider);
for (IFile currentFile : changes.keySet()) {
MultiTextEdit edit = changes.get(currentFile);
@@ -121,145 +140,426 @@ public class ChangeGenerator extends ASTVisitor {
}
}
- private void initParentModList() {
+ private void classifyModifications() {
ASTModificationMap rootModifications = modificationStore.getRootModifications();
- if (rootModifications != null) {
- for (IASTNode modifiedNode : rootModifications.getModifiedNodes()) {
- List<ASTModification> modificationsForNode = rootModifications.getModificationsForNode(modifiedNode);
- IASTNode modifiedNodeParent = determineParentToBeRewritten(modifiedNode, modificationsForNode);
- List<ASTModification> list = modificationParent.get(modifiedNodeParent != null ?
- modifiedNodeParent : modifiedNode);
- if (list != null) {
- list.addAll(modificationsForNode);
- } else {
- List<ASTModification> modifiableList = new ArrayList<ASTModification>(modificationsForNode);
- modificationParent.put(modifiedNodeParent != null ?
- modifiedNodeParent : modifiedNode, modifiableList);
+ if (rootModifications == null)
+ return;
+
+ for (IASTNode node : rootModifications.getModifiedNodes()) {
+ List<ASTModification> modifications = rootModifications.getModificationsForNode(node);
+ for (ASTModification modification : modifications) {
+ Map<ModificationKind, List<ASTModification>> map = classifiedModifications.get(node);
+ if (map == null) {
+ map = new TreeMap<ModificationKind, List<ASTModification>>();
+ classifiedModifications.put(node, map);
}
+ ModificationKind kind = modification.getKind();
+ List<ASTModification> list = map.get(kind);
+ if (list == null) {
+ list = new ArrayList<ASTModification>(2);
+ map.put(kind, list);
+ }
+ list.add(modification);
}
}
}
- private IASTNode determineParentToBeRewritten(IASTNode modifiedNode, List<ASTModification> modificationsForNode) {
- IASTNode modifiedNodeParent = modifiedNode;
- for (ASTModification currentModification : modificationsForNode) {
- if (currentModification.getKind() == ASTModification.ModificationKind.REPLACE) {
- modifiedNodeParent = modifiedNode.getParent();
- break;
- }
+ @Override
+ public int visit(IASTTranslationUnit tu) {
+ IASTFileLocation location = tu.getFileLocation();
+ sourceOffsets.put(location.getFileName(), Integer.valueOf(location.getNodeOffset()));
+ return super.visit(tu);
+ }
+
+ @Override
+ public int leave(IASTTranslationUnit tu) {
+ handleAppends(tu);
+ return super.leave(tu);
+ }
+
+ @Override
+ public int visit(IASTDeclaration declaration) {
+ handleInserts(declaration);
+ if (requiresRewrite(declaration)) {
+ handleReplace(declaration);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(declaration);
+ }
+
+ @Override
+ public int visit(IASTDeclarator declarator) {
+ handleInserts(declarator);
+ if (requiresRewrite(declarator)) {
+ handleReplace(declarator);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(declarator);
+ }
+
+ @Override
+ public int visit(IASTArrayModifier arrayModifier) {
+ handleInserts(arrayModifier);
+ if (requiresRewrite(arrayModifier)) {
+ handleReplace(arrayModifier);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(arrayModifier);
+ }
+
+ @Override
+ public int visit(ICPPASTNamespaceDefinition namespaceDefinition) {
+ handleInserts(namespaceDefinition);
+ if (requiresRewrite(namespaceDefinition)) {
+ handleReplace(namespaceDefinition);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(namespaceDefinition);
+ }
+
+ @Override
+ public int leave(ICPPASTNamespaceDefinition namespaceDefinition) {
+ if (!requiresRewrite(namespaceDefinition)) {
+ handleAppends(namespaceDefinition);
+ }
+ return super.leave(namespaceDefinition);
+ }
+
+ @Override
+ public int visit(IASTDeclSpecifier declSpec) {
+ handleInserts(declSpec);
+ if (requiresRewrite(declSpec)) {
+ handleReplace(declSpec);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(declSpec);
+ }
+
+ @Override
+ public int leave(IASTDeclSpecifier declSpec) {
+ if (!requiresRewrite(declSpec)) {
+ handleAppends(declSpec);
+ }
+ return super.leave(declSpec);
+ }
+
+ @Override
+ public int visit(IASTExpression expression) {
+ handleInserts(expression);
+ if (requiresRewrite(expression)) {
+ handleReplace(expression);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(expression);
+ }
+
+ @Override
+ public int visit(IASTInitializer initializer) {
+ handleInserts(initializer);
+ if (requiresRewrite(initializer)) {
+ handleReplace(initializer);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(initializer);
+ }
+
+ @Override
+ public int visit(IASTName name) {
+ handleInserts(name);
+ if (requiresRewrite(name)) {
+ handleReplace(name);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(name);
+ }
+
+ @Override
+ public int visit(IASTParameterDeclaration parameterDeclaration) {
+ handleInserts(parameterDeclaration);
+ if (requiresRewrite(parameterDeclaration)) {
+ handleReplace(parameterDeclaration);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(parameterDeclaration);
+ }
+
+ @Override
+ public int visit(IASTPointerOperator pointerOperator) {
+ handleInserts(pointerOperator);
+ if (requiresRewrite(pointerOperator)) {
+ handleReplace(pointerOperator);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(pointerOperator);
+ }
+
+ @Override
+ public int visit(IASTTypeId typeId) {
+ handleInserts(typeId);
+ if (requiresRewrite(typeId)) {
+ handleReplace(typeId);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(typeId);
+ }
+
+ @Override
+ public int visit(IASTStatement statement) {
+ handleInserts(statement);
+ if (requiresRewrite(statement)) {
+ handleReplace(statement);
+ return ASTVisitor.PROCESS_SKIP;
+ }
+ return super.visit(statement);
+ }
+
+ @Override
+ public int leave(IASTStatement statement) {
+ if (!requiresRewrite(statement)) {
+ handleAppends(statement);
}
- modifiedNodeParent = modifiedNodeParent != null ? modifiedNodeParent : modifiedNode;
- return modifiedNodeParent;
+ return super.leave(statement);
}
/**
* Applies the C++ code formatter to the code affected by refactoring.
*
- * @param edit The text edit produced by refactoring.
+ * @param multiEdit The text edit produced by refactoring.
* @param file The file being modified.
* @return The text edit containing formatted refactoring changes, or the original text edit
* in case of errors.
*/
- private MultiTextEdit formatChangedCode(MultiTextEdit edit, IFile file) {
+ private MultiTextEdit formatChangedCode(MultiTextEdit multiEdit, IFile file) {
String code;
try {
code = FileContentHelper.getContent(file, 0);
} catch (IOException e) {
CCorePlugin.log(e);
- return edit;
+ return multiEdit;
} catch (CoreException e) {
CCorePlugin.log(e);
- return edit;
+ return multiEdit;
}
IDocument document = new Document(code);
try {
- TextEdit tempEdit = edit.copy();
- tempEdit.apply(document, TextEdit.UPDATE_REGIONS);
- TextEdit[] edits = tempEdit.getChildren();
- IRegion[] regions = new IRegion[edits.length];
+ // Apply refactoring changes to a temporary document.
+ TextEdit edit = multiEdit.copy();
+ edit.apply(document, TextEdit.UPDATE_REGIONS);
+
+ // Expand regions affected by the changes to cover complete lines. We calculate two
+ // sets of regions, reflecting the state of the document before and after
+ // the refactoring changes.
+ TextEdit[] edits = edit.getChildren();
+ TextEdit[] originalEdits = multiEdit.getChildren();
+ IRegion[] regionsAfter = new IRegion[edits.length];
+ IRegion[] regionsBefore = new IRegion[edits.length];
+ int numRegions = 0;
+ int prevEnd = -1;
for (int i = 0; i < edits.length; i++) {
- regions[i] = edits[i].getRegion();
+ edit = edits[i];
+ int offset = edit.getOffset();
+ int end = offset + edit.getLength();
+ int newOffset = document.getLineInformationOfOffset(offset).getOffset();
+ int newEnd = endOffset(document.getLineInformationOfOffset(end));
+ edit = originalEdits[i];
+ int offsetBefore = edit.getOffset();
+ int newOffsetBefore = newOffset + offsetBefore - offset;
+ int newEndBefore = newEnd + offsetBefore + edit.getLength() - end;
+ if (newOffset <= prevEnd) {
+ numRegions--;
+ newOffset = regionsAfter[numRegions].getOffset();
+ newOffsetBefore = regionsBefore[numRegions].getOffset();
+ }
+ prevEnd = newEnd;
+ regionsAfter[numRegions] = new Region(newOffset, newEnd - newOffset);
+ regionsBefore[numRegions] = new Region(newOffsetBefore, newEndBefore - newOffsetBefore);
+ numRegions++;
+ }
+
+ if (numRegions < regionsAfter.length) {
+ regionsAfter = Arrays.copyOf(regionsAfter, numRegions);
+ regionsBefore = Arrays.copyOf(regionsBefore, numRegions);
}
+
+ // Calculate formatting changes for the regions after the refactoring changes.
ICProject project = CCorePlugin.getDefault().getCoreModel().create(file.getProject());
Map<String, String> options = project.getOptions(true);
+ // Allow all comments to be indented.
+ options.put(DefaultCodeFormatterConstants.FORMATTER_COMMENT_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN,
+ DefaultCodeFormatterConstants.FALSE);
CodeFormatter formatter = ToolFactory.createCodeFormatter(options);
code = document.get();
TextEdit[] formatEdits = formatter.format(CCodeFormatter.K_TRANSLATION_UNIT, code,
- regions, TextUtilities.getDefaultLineDelimiter(document));
+ regionsAfter, TextUtilities.getDefaultLineDelimiter(document));
+
+ // For each of the regions we apply formatting changes and create a ReplaceEdit using
+ // the region before the refactoring changes and the text after the formatting changes.
MultiTextEdit resultEdit = new MultiTextEdit();
- edits = edit.getChildren();
- for (int i = 0; i < edits.length; i++) {
- IRegion region = regions[i];
+ for (int i = 0; i < regionsAfter.length; i++) {
+ IRegion region = regionsAfter[i];
int offset = region.getOffset();
- TextEdit formatEdit = formatEdits[i];
- formatEdit.moveTree(-offset);
+ edit = formatEdits[i];
+ edit.moveTree(-offset);
document = new Document(code.substring(offset, offset + region.getLength()));
- formatEdit.apply(document, TextEdit.NONE);
- TextEdit textEdit = edits[i];
- resultEdit.addChild(
- new ReplaceEdit(textEdit.getOffset(), textEdit.getLength(), document.get()));
+ edit.apply(document, TextEdit.NONE);
+ region = regionsBefore[i];
+ edit = new ReplaceEdit(region.getOffset(), region.getLength(), document.get());
+ resultEdit.addChild(edit);
}
return resultEdit;
} catch (MalformedTreeException e) {
CCorePlugin.log(e);
- return edit;
+ return multiEdit;
} catch (BadLocationException e) {
CCorePlugin.log(e);
- return edit;
+ return multiEdit;
}
}
- @Override
- public int visit(IASTTranslationUnit translationUnit) {
- if (hasChangedChild(translationUnit)) {
- synthTreatment(translationUnit);
- }
- IASTFileLocation location = translationUnit.getFileLocation();
- sourceOffsets.put(location.getFileName(), Integer.valueOf(location.getNodeOffset()));
- return super.visit(translationUnit);
+ private int endOffset(IRegion region) {
+ return region.getOffset() + region.getLength();
}
- @Override
- public int leave(IASTTranslationUnit tu) {
- return super.leave(tu);
+ private int endOffset(IASTFileLocation nodeLocation) {
+ return nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
}
- @Override
- public int visit(IASTDeclaration declaration) {
- if (hasChangedChild(declaration)) {
- synthTreatment(declaration);
- return ASTVisitor.PROCESS_SKIP;
+ private int endOffset(IASTNode node) {
+ return endOffset(node.getFileLocation());
+ }
+
+ private int offset(IASTNode node) {
+ return node.getFileLocation().getNodeOffset();
+ }
+
+ private void handleInserts(IASTNode anchorNode) {
+ List<ASTModification> modifications = getModifications(anchorNode, ModificationKind.INSERT_BEFORE);
+ if (modifications.isEmpty())
+ return;
+ ChangeGeneratorWriterVisitor writer =
+ new ChangeGeneratorWriterVisitor(modificationStore, commentMap);
+ IASTNode newNode = null;
+ for (ASTModification modification : modifications) {
+ boolean first = newNode == null;
+ newNode = modification.getNewNode();
+ if (first) {
+ IASTNode prevNode = getPreviousSiblingOrPreprocessorNode(anchorNode);
+ if (prevNode != null) {
+ if (ASTWriter.requireBlankLineInBetween(prevNode, newNode)) {
+ writer.newLine();
+ }
+ } else if (anchorNode.getParent() instanceof ICPPASTNamespaceDefinition) {
+ writer.newLine();
+ }
+ }
+ newNode.accept(writer);
+ if (getContainingNodeList(anchorNode) != null) {
+ writer.getScribe().print(", "); //$NON-NLS-1$
+ }
}
- return super.visit(declaration);
+ if (ASTWriter.requireBlankLineInBetween(newNode, anchorNode)) {
+ writer.newLine();
+ }
+ int insertPos = getOffsetIncludingComments(anchorNode);
+ int length = 0;
+ if (writer.getScribe().isAtBeginningOfLine()) {
+ String tuCode = anchorNode.getTranslationUnit().getRawSignature();
+ insertPos = skipPrecedingWhitespace(tuCode, insertPos);
+ length = insertPos;
+ insertPos = skipPrecedingBlankLines(tuCode, insertPos);
+ length -= insertPos;
+ }
+ String code = writer.toString();
+ ReplaceEdit edit = new ReplaceEdit(insertPos, length, code);
+ IFile file = FileHelper.getFileFromNode(anchorNode);
+ MultiTextEdit parentEdit = getEdit(anchorNode, file);
+ parentEdit.addChild(edit);
+ sourceOffsets.put(file.getName(), Integer.valueOf(edit.getOffset()));
}
- private void synthTreatment(IASTNode synthNode) {
+ private void handleReplace(IASTNode node) {
+ List<ASTModification> modifications = getModifications(node, ModificationKind.REPLACE);
+ String source = node.getTranslationUnit().getRawSignature();
+ TextEdit edit;
ChangeGeneratorWriterVisitor writer =
new ChangeGeneratorWriterVisitor(modificationStore, commentMap);
- synthNode.accept(writer);
- String synthSource = writer.toString();
- createChange(synthNode, synthSource);
+ if (modifications.size() == 1 && modifications.get(0).getNewNode() == null) {
+ int offset = getOffsetIncludingComments(node);
+ int endOffset = getEndOffsetIncludingComments(node);
+ offset = skipPrecedingBlankLines(source, offset);
+ endOffset = skipTrailingBlankLines(source, endOffset);
+ IASTNode[] siblingsList = getContainingNodeList(node);
+ if (siblingsList != null) {
+ if (siblingsList.length > 1) {
+ if (node == siblingsList[0]) {
+ endOffset = skipToTrailingDelimiter(source, ',', endOffset);
+ } else {
+ offset = skipToPrecedingDelimiter(source, ',', offset);
+ }
+ } else if (node.getPropertyInParent() == ICPPASTFunctionDefinition.MEMBER_INITIALIZER) {
+ offset = skipToPrecedingDelimiter(source, ':', offset);
+ }
+ }
+ IASTNode prevNode = getPreviousSiblingOrPreprocessorNode(node);
+ IASTNode nextNode = getNextSiblingOrPreprocessorNode(node);
+ if (prevNode != null && nextNode != null) {
+ if (ASTWriter.requireBlankLineInBetween(prevNode, nextNode)) {
+ writer.newLine();
+ }
+ } else if (node.getParent() instanceof ICPPASTNamespaceDefinition) {
+ writer.newLine();
+ }
+ String code = writer.toString();
+ edit = new ReplaceEdit(offset, endOffset - offset, code);
+ } else {
+ node.accept(writer);
+ String code = writer.toString();
+ IASTFileLocation location = node.getFileLocation();
+ int offset = location.getNodeOffset();
+ int endOffset = offset + location.getNodeLength();
+ if (node instanceof IASTStatement || node instanceof IASTDeclaration) {
+ // Include trailing comments in the area to be replaced.
+ endOffset = Math.max(endOffset, getEndOffsetIncludingTrailingComments(node));
+ }
+ String lineSeparator = writer.getScribe().getLineSeparator();
+ if (code.endsWith(lineSeparator)) {
+ code = code.substring(0, code.length() - lineSeparator.length());
+ }
+ edit = new ReplaceEdit(offset, endOffset - offset, code);
+ }
+ IFile file = FileHelper.getFileFromNode(node);
+ MultiTextEdit parentEdit = getEdit(node, file);
+ parentEdit.addChild(edit);
- IASTFileLocation fileLocation = synthNode.getFileLocation();
+ IASTFileLocation fileLocation = node.getFileLocation();
int newOffset = fileLocation.getNodeOffset() + fileLocation.getNodeLength();
sourceOffsets.put(fileLocation.getFileName(), Integer.valueOf(newOffset));
}
private void handleAppends(IASTNode node) {
+ List<ASTModification> modifications = getModifications(node, ModificationKind.APPEND_CHILD);
+ if (modifications.isEmpty())
+ return;
ChangeGeneratorWriterVisitor writer =
new ChangeGeneratorWriterVisitor(modificationStore, commentMap);
- List<ASTModification> modifications = modificationParent.get(node);
ReplaceEdit anchor = getAppendAnchor(node);
Assert.isNotNull(anchor);
IASTNode precedingNode = getLastNodeBeforeAppendPoint(node);
- if (precedingNode != null &&
- ASTWriter.requireBlankLineInBetween(precedingNode, modifications.get(0).getNewNode())) {
- writer.newLine();
- }
for (ASTModification modification : modifications) {
IASTNode newNode = modification.getNewNode();
+ if (precedingNode != null) {
+ if (ASTWriter.requireBlankLineInBetween(precedingNode, newNode)) {
+ writer.newLine();
+ }
+ } else if (node instanceof ICPPASTNamespaceDefinition) {
+ writer.newLine();
+ }
+ precedingNode = null;
newNode.accept(writer);
}
+ if (node instanceof ICPPASTNamespaceDefinition) {
+ writer.newLine();
+ }
String code = writer.toString();
IFile file = FileHelper.getFileFromNode(node);
MultiTextEdit parentEdit = getEdit(node, file);
@@ -271,29 +571,217 @@ public class ChangeGenerator extends ASTVisitor {
sourceOffsets.put(fileLocation.getFileName(), Integer.valueOf(newOffset));
}
+ private void handleAppends(IASTTranslationUnit tu) {
+ ASTWriter synthWriter = new ASTWriter();
+ synthWriter.setModificationStore(modificationStore);
+
+ for (ASTModification modification : getModifications(tu, ModificationKind.APPEND_CHILD)) {
+ IASTNode targetNode = modification.getTargetNode();
+ IASTFileLocation targetLocation = targetNode.getFileLocation();
+ String currentFile = targetLocation.getFileName();
+ IPath implPath = new Path(currentFile);
+ IFile relevantFile= ResourceLookup.selectFileForLocation(implPath, null);
+ if (relevantFile == null || !relevantFile.exists()) { // If not in workspace or local file system
+ throw new UnhandledASTModificationException(modification);
+ }
+ MultiTextEdit edit;
+ if (changes.containsKey(relevantFile)) {
+ edit = changes.get(relevantFile);
+ } else {
+ edit = new MultiTextEdit();
+ changes.put(relevantFile, edit);
+ }
+ String code = synthWriter.write(modification.getNewNode(), commentMap);
+
+ if (targetNode instanceof IASTTranslationUnit &&
+ ((IASTTranslationUnit) targetNode).getDeclarations().length > 0) {
+ IASTTranslationUnit targetTu = (IASTTranslationUnit) targetNode;
+ IASTDeclaration lastDecl = targetTu.getDeclarations()[targetTu.getDeclarations().length - 1];
+ targetLocation = lastDecl.getFileLocation();
+ }
+ String lineDelimiter = FileHelper.determineLineDelimiter(
+ FileHelper.getFileFromNode(targetNode));
+ edit.addChild(new InsertEdit(endOffset(targetLocation), lineDelimiter + lineDelimiter + code));
+ }
+ }
+
+ /**
+ * Returns the list of nodes the given node is part of, for example function parameters if
+ * the node is a parameter.
+ *
+ * @param node the node possibly belonging to a list.
+ * @return the list of nodes containing the given node, or <code>null</code> if the node
+ * does not belong to a list
+ */
+ private IASTNode[] getContainingNodeList(IASTNode node) {
+ if (node.getPropertyInParent() == IASTStandardFunctionDeclarator.FUNCTION_PARAMETER) {
+ return ((IASTStandardFunctionDeclarator) node.getParent()).getParameters();
+ } else if (node.getPropertyInParent() == IASTExpressionList.NESTED_EXPRESSION) {
+ return ((IASTExpressionList) node.getParent()).getExpressions();
+ } else if (node.getPropertyInParent() == ICPPASTFunctionDefinition.MEMBER_INITIALIZER) {
+ return ((ICPPASTFunctionDefinition) node.getParent()).getMemberInitializers();
+ } else if (node.getPropertyInParent() == ICPPASTFunctionDeclarator.EXCEPTION_TYPEID) {
+ return ((ICPPASTFunctionDeclarator) node.getParent()).getExceptionSpecification();
+ }
+
+ return null;
+ }
+
private IASTNode getLastNodeBeforeAppendPoint(IASTNode node) {
IASTNode[] children;
- if (node instanceof IASTCompositeTypeSpecifier) {
+ if (node instanceof ICPPASTNamespaceDefinition) {
+ children = ((ICPPASTNamespaceDefinition) node).getDeclarations(true);
+ } else if (node instanceof IASTCompositeTypeSpecifier) {
children = ((IASTCompositeTypeSpecifier) node).getDeclarations(true);
} else {
children = node.getChildren();
}
- return children.length > 0 ? children[children.length - 1] : null;
+ for (int i = children.length; --i >= 0;) {
+ IASTNode child = getReplacementNode(children[i]);
+ if (child != null)
+ return child;
+ }
+ return null;
}
- private boolean isAppendable(Iterable<ASTModification> modifications) {
- for (ASTModification modification : modifications) {
- if (!isAppendable(modification))
+ private IASTNode getReplacementNode(IASTNode node) {
+ List<ASTModification> modifications = getModifications(node, ModificationKind.REPLACE);
+ if (!modifications.isEmpty()) {
+ node = modifications.get(modifications.size() - 1).getNewNode();
+ }
+ return node;
+ }
+
+ private IASTNode getPreviousSiblingNode(IASTNode node) {
+ IASTNode parent = node.getParent();
+ IASTNode[] siblings;
+ if (parent instanceof ICPPASTNamespaceDefinition) {
+ siblings = ((ICPPASTNamespaceDefinition) parent).getDeclarations(true);
+ } else if (parent instanceof IASTCompositeTypeSpecifier) {
+ siblings = ((IASTCompositeTypeSpecifier) parent).getDeclarations(true);
+ } else {
+ siblings = parent.getChildren();
+ }
+ boolean beforeNode = false;
+ for (int i = siblings.length; --i >= 0;) {
+ IASTNode sibling = siblings[i];
+ if (sibling == node) {
+ beforeNode = true;
+ } else if (beforeNode) {
+ sibling = getReplacementNode(sibling);
+ if (sibling != null)
+ return sibling;
+ }
+ }
+ return null;
+ }
+
+ private IASTNode getPreviousSiblingOrPreprocessorNode(IASTNode node) {
+ int offset = offset(node);
+ IASTTranslationUnit ast = node.getTranslationUnit();
+ IASTPreprocessorStatement[] preprocessorStatements = ast.getAllPreprocessorStatements();
+ int low = 0;
+ int high = preprocessorStatements.length;
+ while (low < high) {
+ int mid = (low + high) / 2;
+ IASTNode statement = preprocessorStatements[mid];
+ if (statement.isPartOfTranslationUnitFile() && endOffset(statement) > offset) {
+ high = mid;
+ } else {
+ low = mid + 1;
+ }
+ }
+ low--;
+ if (low >= 0) {
+ IASTNode statement = preprocessorStatements[low];
+ if (statement.isPartOfTranslationUnitFile()) {
+ int endOffset = endOffset(statement);
+ if (!doesRegionContainNode(ast, endOffset, offset - endOffset)) {
+ return statement;
+ }
+ }
+ }
+
+ return getPreviousSiblingNode(node);
+ }
+
+ private IASTNode getNextSiblingNode(IASTNode node) {
+ IASTNode parent = node.getParent();
+ IASTNode[] siblings;
+ if (parent instanceof ICPPASTNamespaceDefinition) {
+ siblings = ((ICPPASTNamespaceDefinition) parent).getDeclarations(true);
+ } else if (parent instanceof IASTCompositeTypeSpecifier) {
+ siblings = ((IASTCompositeTypeSpecifier) parent).getDeclarations(true);
+ } else {
+ siblings = parent.getChildren();
+ }
+ boolean beforeNode = false;
+ for (int i = 0; i < siblings.length; i++) {
+ IASTNode sibling = siblings[i];
+ if (sibling == node) {
+ beforeNode = true;
+ } else if (beforeNode) {
+ sibling = getReplacementNode(sibling);
+ if (sibling != null)
+ return sibling;
+ }
+ }
+ return null;
+ }
+
+ private IASTNode getNextSiblingOrPreprocessorNode(IASTNode node) {
+ int endOffset = endOffset(node);
+ IASTTranslationUnit ast = node.getTranslationUnit();
+ IASTPreprocessorStatement[] preprocessorStatements = ast.getAllPreprocessorStatements();
+ int low = 0;
+ int high = preprocessorStatements.length;
+ while (low < high) {
+ int mid = (low + high) / 2;
+ IASTNode statement = preprocessorStatements[mid];
+ if (statement.isPartOfTranslationUnitFile() && offset(statement) > endOffset) {
+ high = mid;
+ } else {
+ low = mid + 1;
+ }
+ }
+ if (high < preprocessorStatements.length) {
+ IASTNode statement = preprocessorStatements[high];
+ if (statement.isPartOfTranslationUnitFile()) {
+ int offset = offset(statement);
+ if (!doesRegionContainNode(ast, endOffset, offset - endOffset)) {
+ return statement;
+ }
+ }
+ }
+
+ return getNextSiblingNode(node);
+ }
+
+ /**
+ * Checks if a given region contains at least a piece of a node after rewrite.
+ */
+ private boolean doesRegionContainNode(IASTTranslationUnit ast, int offset, int length) {
+ IASTNodeSelector nodeSelector = ast.getNodeSelector(ast.getFilePath());
+ while (length > 0) {
+ IASTNode node = nodeSelector.findFirstContainedNode(offset, length - 1);
+ if (node == null)
return false;
+ if (!isNodeRemoved(node))
+ return true;
+ int oldOffset = offset;
+ offset = endOffset(node);
+ length -= offset - oldOffset;
}
- return true;
+ return false;
}
- private boolean isAppendable(ASTModification modification) {
- if (modification.getKind() != ModificationKind.APPEND_CHILD)
- return false;
- IASTNode node = modification.getNewNode();
- return node instanceof IASTDeclaration || node instanceof IASTStatement;
+ private boolean isNodeRemoved(IASTNode node) {
+ do {
+ if (getReplacementNode(node) == null)
+ return true;
+ } while ((node = node.getParent()) != null);
+
+ return false;
}
/**
@@ -310,93 +798,148 @@ public class ChangeGenerator extends ASTVisitor {
node instanceof ICPPASTNamespaceDefinition)) {
return null;
}
- IFile file = FileHelper.getFileFromNode(node);
- String code = originalCodeOfNode(node, file);
+ String code = node.getRawSignature();
IASTFileLocation location = node.getFileLocation();
int pos = location.getNodeOffset() + location.getNodeLength();
int len = code.endsWith("}") ? 1 : 0; //$NON-NLS-1$
- int startOfLine = skipPrecedingBlankLines(code, code.length() - len);
- if (startOfLine < 0) {
+ int insertPos = code.length() - len;
+ int startOfLine = skipPrecedingBlankLines(code, insertPos);
+ if (startOfLine == insertPos) {
// Include the closing brace in the region that will be reformatted.
- return new ReplaceEdit(pos - len, len, code.substring(code.length() - len));
+ return new ReplaceEdit(pos - len, len, code.substring(insertPos));
}
- return new ReplaceEdit(location.getNodeOffset() + startOfLine, 0, ""); //$NON-NLS-1$
+ return new ReplaceEdit(location.getNodeOffset() + startOfLine, insertPos - startOfLine, ""); //$NON-NLS-1$
}
/**
- * Skips blank lines preceding the given position.
- * @param text the text to scan
- * @param pos the position after that blank lines.
- * @return the beginning of the first blank line, or -1 if the beginning of the line
- * corresponding to the given position contains non-whitespace characters.
+ * Skips whitespace between the beginning of the line and the given position.
+ *
+ * @param text The text to scan.
+ * @param startPos The start position.
+ * @return The beginning of the line containing the start position, if there are no
+ * non-whitespace characters between the beginning of the line and the start position.
+ * Otherwise returns the start position.
*/
- private int skipPrecedingBlankLines(String text, int pos) {
- int lineStart = -1;
- while (--pos >= 0) {
+ private int skipPrecedingWhitespace(String text, int startPos) {
+ for (int pos = startPos; --pos >= 0; ) {
char c = text.charAt(pos);
if (c == '\n') {
- lineStart = pos + 1;
+ return pos + 1;
} else if (!Character.isWhitespace(c)) {
- break;
+ return startPos;
}
}
- return lineStart;
+ return 0;
}
- private void synthTreatment(IASTTranslationUnit synthTU) {
- ASTWriter synthWriter = new ASTWriter();
- synthWriter.setModificationStore(modificationStore);
+ /**
+ * Skips whitespace between the beginning of the line and the given position and blank lines
+ * above that.
+ *
+ * @param text The text to scan.
+ * @param startPos The start position.
+ * @return The beginning of the first blank line preceding the start position,
+ * or beginning of the current line, if there are no non-whitespace characters between
+ * the beginning of the line and the start position.
+ * Otherwise returns the start position.
+ */
+ private int skipPrecedingBlankLines(String text, int startPos) {
+ for (int pos = startPos; --pos >= 0;) {
+ char c = text.charAt(pos);
+ if (c == '\n') {
+ startPos = pos + 1;
+ } else if (!Character.isWhitespace(c)) {
+ return startPos;
+ }
+ }
+ return 0;
+ }
- for (ASTModification modification : modificationParent.get(synthTU)) {
- IASTNode targetNode = modification.getTargetNode();
- IASTFileLocation targetLocation = targetNode.getFileLocation();
- String currentFile = targetLocation.getFileName();
- IPath implPath = new Path(currentFile);
- IFile relevantFile= ResourceLookup.selectFileForLocation(implPath, null);
- if (relevantFile == null || !relevantFile.exists()) { // If not in workspace or local file system
- throw new UnhandledASTModificationException(modification);
+ /**
+ * Skips whitespace between the given position and the end of the line.
+ *
+ * @param text The text to scan.
+ * @param startPos The start position.
+ * @return The end of the line containing the start position, if there are no non-whitespace
+ * characters between the start position and the end of the line.
+ * Otherwise returns the start position.
+ */
+ private int skipTrailingWhitespace(String text, int startPos) {
+ for (int pos = startPos; pos < text.length(); pos++) {
+ char c = text.charAt(pos);
+ if (c == '\n') {
+ return pos + 1;
+ } else if (!Character.isWhitespace(c)) {
+ return startPos;
}
- MultiTextEdit edit;
- if (changes.containsKey(relevantFile)) {
- edit = changes.get(relevantFile);
- } else {
- edit = new MultiTextEdit();
- changes.put(relevantFile, edit);
+ }
+ return text.length();
+ }
+
+ /**
+ * Skips whitespace between the given position and the end of the line and blank lines
+ * below that.
+ *
+ * @param text The text to scan.
+ * @param startPos The start position.
+ * @return The beginning of the first non-blank line following the start position, if there are
+ * no non-whitespace characters between the start position and the end of the line.
+ * Otherwise returns the start position.
+ */
+ private int skipTrailingBlankLines(String text, int startPos) {
+ for (int pos = startPos; pos < text.length(); pos++) {
+ char c = text.charAt(pos);
+ if (c == '\n') {
+ startPos = pos + 1;
+ } else if (!Character.isWhitespace(c)) {
+ return startPos;
}
- String newNodeCode = synthWriter.write(modification.getNewNode(), commentMap);
-
- switch (modification.getKind()) {
- case REPLACE:
- edit.addChild(new ReplaceEdit(targetLocation.getNodeOffset(),
- targetLocation.getNodeLength(), newNodeCode));
- break;
- case INSERT_BEFORE:
- if (ASTWriter.requireBlankLineInBetween(modification.getNewNode(), targetNode)) {
- newNodeCode = newNodeCode + "\n"; //$NON-NLS-1$
- }
- edit.addChild(new InsertEdit(getOffsetIncludingComments(targetNode), newNodeCode));
- break;
- case APPEND_CHILD:
- if (targetNode instanceof IASTTranslationUnit &&
- ((IASTTranslationUnit) targetNode).getDeclarations().length > 0) {
- IASTTranslationUnit tu = (IASTTranslationUnit) targetNode;
- IASTDeclaration lastDecl = tu.getDeclarations()[tu.getDeclarations().length - 1];
- targetLocation = lastDecl.getFileLocation();
- }
- String lineDelimiter = FileHelper.determineLineDelimiter(
- FileHelper.getFileFromNode(targetNode));
- edit.addChild(new InsertEdit(targetLocation.getNodeOffset() + targetLocation.getNodeLength(),
- lineDelimiter + lineDelimiter + newNodeCode));
- break;
+ }
+ return text.length();
+ }
+
+ /**
+ * Skips whitespace to the left of the given position until the given delimiter character
+ * is found.
+ *
+ * @param text The text to scan.
+ * @param delimiter the delimiter to find
+ * @param startPos The start position.
+ * @return The position of the given delimiter, or the start position if a non-whitespace
+ * character is encountered before the given delimiter.
+ */
+ private int skipToPrecedingDelimiter(String text, char delimiter, int startPos) {
+ for (int pos = startPos; --pos >= 0; ) {
+ char c = text.charAt(pos);
+ if (c == delimiter) {
+ return pos;
+ } else if (!Character.isWhitespace(c)) {
+ return startPos;
}
}
+ return startPos;
}
- private void createChange(IASTNode synthNode, String synthSource) {
- IFile relevantFile = FileHelper.getFileFromNode(synthNode);
- String originalCode = originalCodeOfNode(synthNode, relevantFile);
- CodeComparer codeComparer = new CodeComparer(originalCode, synthSource);
- codeComparer.createChange(getEdit(synthNode, relevantFile), synthNode);
+ /**
+ * Skips whitespace to the right of the given position until the given delimiter character
+ * is found.
+ *
+ * @param text The text to scan.
+ * @param delimiter the delimiter to find
+ * @param startPos The start position.
+ * @return The position after the given delimiter, or the start position if a non-whitespace
+ * character is encountered before the given delimiter.
+ */
+ private int skipToTrailingDelimiter(String text, char delimiter, int startPos) {
+ for (int pos = startPos; pos < text.length(); pos++) {
+ char c = text.charAt(pos);
+ if (c == delimiter) {
+ return pos + 1;
+ } else if (!Character.isWhitespace(c)) {
+ return startPos;
+ }
+ }
+ return startPos;
}
private MultiTextEdit getEdit(IASTNode modifiedNode, IFile file) {
@@ -406,366 +949,108 @@ public class ChangeGenerator extends ASTVisitor {
changes.put(file, edit);
}
TextEditGroup editGroup = new TextEditGroup(Messages.ChangeGenerator_group);
- for (ASTModification currentModification : modificationParent.get(modifiedNode)) {
- if (currentModification.getAssociatedEditGroup() != null) {
- editGroup = currentModification.getAssociatedEditGroup();
- edit.addChildren(editGroup.getTextEdits());
- break;
+ for (List<ASTModification> modifications : getModifications(modifiedNode).values()) {
+ for (ASTModification modification : modifications) {
+ if (modification.getAssociatedEditGroup() != null) {
+ editGroup = modification.getAssociatedEditGroup();
+ edit.addChildren(editGroup.getTextEdits());
+ return edit;
+ }
}
}
return edit;
}
- private String originalCodeOfNode(IASTNode node, IFile sourceFile) {
- int nodeOffset = getOffsetIncludingComments(node);
- int nodeLength = getNodeLengthIncludingComments(node);
- return FileContentHelper.getContent(sourceFile, nodeOffset, nodeLength);
- }
-
- private int getNodeLengthIncludingComments(IASTNode node) {
+ private int getOffsetIncludingComments(IASTNode node) {
int nodeOffset = node.getFileLocation().getNodeOffset();
- int nodeLength = node.getFileLocation().getNodeLength();
- ArrayList<IASTComment> comments = commentMap.getAllCommentsForNode(node);
+ List<IASTComment> comments = commentMap.getAllCommentsForNode(node);
if (!comments.isEmpty()) {
int startOffset = nodeOffset;
- int endOffset = nodeOffset + nodeLength;
for (IASTComment comment : comments) {
IASTFileLocation commentLocation = comment.getFileLocation();
if (commentLocation.getNodeOffset() < startOffset) {
startOffset = commentLocation.getNodeOffset();
}
- if (commentLocation.getNodeOffset() + commentLocation.getNodeLength() >= endOffset) {
- endOffset = commentLocation.getNodeOffset() + commentLocation.getNodeLength();
- }
}
- nodeLength = endOffset - startOffset;
+ nodeOffset = startOffset;
}
- return nodeLength;
+ return nodeOffset;
}
- private int getOffsetIncludingComments(IASTNode node) {
- int nodeOffset = node.getFileLocation().getNodeOffset();
+ private int getEndOffsetIncludingComments(IASTNode node) {
+ IASTFileLocation nodeLocation = node.getFileLocation();
+ int endOffset = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
- ArrayList<IASTComment> comments = commentMap.getAllCommentsForNode(node);
+ List<IASTComment> comments = commentMap.getAllCommentsForNode(node);
if (!comments.isEmpty()) {
- int startOffset = nodeOffset;
for (IASTComment comment : comments) {
- IASTFileLocation commentLocation = comment.getFileLocation();
- if (commentLocation.getNodeOffset() < startOffset) {
- startOffset = commentLocation.getNodeOffset();
+ int commentEndOffset = endOffset(comment.getFileLocation());
+ if (commentEndOffset >= endOffset) {
+ endOffset = commentEndOffset;
}
}
- nodeOffset = startOffset;
}
- return nodeOffset;
+ return endOffset;
}
- private boolean hasChangedChild(IASTNode node) {
- return modificationParent.containsKey(node);
- }
+ private int getEndOffsetIncludingTrailingComments(IASTNode node) {
+ IASTFileLocation nodeLocation = node.getFileLocation();
+ int endOffset = nodeLocation.getNodeOffset() + nodeLocation.getNodeLength();
- private boolean hasAppendsOnly(IASTNode node) {
- List<ASTModification> modifications = modificationParent.get(node);
- if (modifications == null)
- return false;
- return isAppendable(modifications);
- }
-
- @Override
- public int visit(IASTDeclarator declarator) {
- if (hasChangedChild(declarator)) {
- synthTreatment(declarator);
- return ASTVisitor.PROCESS_SKIP;
- }
- return super.visit(declarator);
- }
-
- @Override
- public int visit(IASTArrayModifier mod) {
- if (hasChangedChild(mod)) {
- synthTreatment(mod);
- return ASTVisitor.PROCESS_SKIP;
- }
- return super.visit(mod);
- }
-
- @Override
- public int visit(ICPPASTNamespaceDefinition namespaceDefinition) {
- if (hasChangedChild(namespaceDefinition) && !hasAppendsOnly(namespaceDefinition)) {
- synthTreatment(namespaceDefinition);
- return ASTVisitor.PROCESS_SKIP;
- }
- return super.visit(namespaceDefinition);
- }
-
- @Override
- public int leave(ICPPASTNamespaceDefinition namespaceDefinition) {
- if (hasAppendsOnly(namespaceDefinition)) {
- handleAppends(namespaceDefinition);
- }
- return super.leave(namespaceDefinition);
- }
-
- @Override
- public int visit(IASTDeclSpecifier declSpec) {
- if (hasChangedChild(declSpec) && !hasAppendsOnly(declSpec)) {
- synthTreatment(declSpec);
- return ASTVisitor.PROCESS_SKIP;
- }
- return super.visit(declSpec);
- }
-
- @Override
- public int leave(IASTDeclSpecifier declSpec) {
- if (hasAppendsOnly(declSpec)) {
- handleAppends(declSpec);
- }
- return super.leave(declSpec);
- }
-
- @Override
- public int visit(IASTExpression expression) {
- if (hasChangedChild(expression)) {
- synthTreatment(expression);
- return ASTVisitor.PROCESS_SKIP;
- }
- return super.visit(expression);
- }
-
- @Override
- public int visit(IASTInitializer initializer) {
- if (hasChangedChild(initializer)) {
- synthTreatment(initializer);
- return ASTVisitor.PROCESS_SKIP;
- }
- return super.visit(initializer);
- }
-
- @Override
- public int visit(IASTName name) {
- if (hasChangedChild(name)) {
- synthTreatment(name);
- return ASTVisitor.PROCESS_SKIP;
+ List<IASTComment> comments = commentMap.getTrailingCommentsForNode(node);
+ if (!comments.isEmpty()) {
+ for (IASTComment comment : comments) {
+ int commentEndOffset = endOffset(comment.getFileLocation());
+ if (commentEndOffset >= endOffset) {
+ endOffset = commentEndOffset;
+ }
+ }
}
- return super.visit(name);
- }
-
- @Override
- public int visit(IASTParameterDeclaration parameterDeclaration) {
- if (hasChangedChild(parameterDeclaration)) {
- synthTreatment(parameterDeclaration);
- return ASTVisitor.PROCESS_SKIP;
+ // TODO(sprigogin): Remove when comments are always assigned to the outermost nodes.
+ if (node instanceof ICPPASTFunctionWithTryBlock) {
+ ICPPASTCatchHandler[] catchHandlers = ((ICPPASTFunctionWithTryBlock) node).getCatchHandlers();
+ if (catchHandlers.length > 0) {
+ endOffset = Math.max(endOffset,
+ getEndOffsetIncludingTrailingComments(catchHandlers[catchHandlers.length - 1]));
+ }
+ } else if (node instanceof IASTFunctionDefinition) {
+ endOffset = Math.max(endOffset,
+ getEndOffsetIncludingTrailingComments(((IASTFunctionDefinition) node).getBody()));
}
- return super.visit(parameterDeclaration);
+ return endOffset;
}
- @Override
- public int visit(IASTStatement statement) {
- if (hasChangedChild(statement) && !hasAppendsOnly(statement)) {
- synthTreatment(statement);
- return ASTVisitor.PROCESS_SKIP;
- }
- return super.visit(statement);
+ private Map<ModificationKind, List<ASTModification>> getModifications(IASTNode node) {
+ Map<ModificationKind, List<ASTModification>> modifications = classifiedModifications.get(node);
+ if (modifications == null)
+ return Collections.emptyMap();
+ return modifications;
}
- @Override
- public int leave(IASTStatement statement) {
- if (hasAppendsOnly(statement)) {
- handleAppends(statement);
- }
- return super.leave(statement);
+ private List<ASTModification> getModifications(IASTNode node, ModificationKind kind) {
+ Map<ModificationKind, List<ASTModification>> allModifications = getModifications(node);
+ List<ASTModification> modifications = allModifications.get(kind);
+ if (modifications == null)
+ return Collections.emptyList();
+ return modifications;
}
- class CodeComparer {
- private final StringBuilder originalCode;
- private final StringBuilder synthCode;
- private int lastCommonInSynthStart;
- private int lastCommonInOriginalStart;
- private int firstCommonInSynthEnd;
- private int firstCommonInOriginalEnd;
-
- public CodeComparer(String originalCode, String synthCode) {
- this.originalCode = new StringBuilder(originalCode);
- this.synthCode = new StringBuilder(synthCode);
- calculatePositions();
- }
-
- private void calculatePositions() {
- lastCommonInSynthStart = calcLastCommonPositionInSynthCode();
- lastCommonInOriginalStart = calcLastCommonPositionInOriginalCode();
- firstCommonInSynthEnd =
- calcFirstPositionOfCommonEndInSynthCode(lastCommonInSynthStart, lastCommonInOriginalStart);
- firstCommonInOriginalEnd =
- calcFirstPositionOfCommonEndInOriginalCode(lastCommonInOriginalStart, lastCommonInSynthStart);
- trimTrailingNewlines();
- }
-
- private void trimTrailingNewlines() {
- int prevOrigEnd = firstCommonInOriginalEnd - 1;
- while (prevOrigEnd > lastCommonInOriginalStart && prevOrigEnd > -1 &&
- isUninterresting(originalCode, prevOrigEnd)) {
- firstCommonInOriginalEnd = prevOrigEnd;
- prevOrigEnd--;
- }
-
- while (firstCommonInOriginalEnd > 0 && firstCommonInOriginalEnd + 1 < originalCode.length() &&
- (originalCode.charAt(firstCommonInOriginalEnd) == ' ' || originalCode.charAt(firstCommonInOriginalEnd) == '\t')) {
- firstCommonInOriginalEnd++;
- }
-
- int prevSynthEnd = firstCommonInSynthEnd - 1;
- while (prevSynthEnd > lastCommonInSynthStart && prevSynthEnd > -1 &&
- isUninterresting(synthCode, prevSynthEnd)) {
- firstCommonInSynthEnd = prevSynthEnd;
- prevSynthEnd--;
- }
- while (firstCommonInSynthEnd > 0 && firstCommonInSynthEnd + 1 < synthCode.length() &&
- (synthCode.charAt(firstCommonInSynthEnd) == ' ' || synthCode.charAt(firstCommonInSynthEnd) == '\t')) {
- firstCommonInSynthEnd++;
- }
- }
-
- public int getLastCommonPositionInSynthCode() {
- return lastCommonInSynthStart;
- }
-
- public int getLastCommonPositionInOriginalCode() {
- return lastCommonInOriginalStart;
- }
-
- public int getFirstPositionOfCommonEndInOriginalCode() {
- return firstCommonInOriginalEnd;
- }
-
- public int getFirstPositionOfCommonEndInSynthCode() {
- return firstCommonInSynthEnd;
- }
-
- public int calcLastCommonPositionInSynthCode() {
- return findLastCommonPosition(synthCode, originalCode);
- }
-
- public int calcLastCommonPositionInOriginalCode() {
- return findLastCommonPosition(originalCode, synthCode);
- }
-
- private int calcFirstPositionOfCommonEndInOriginalCode(int originalLimit, int synthLimit) {
- StringBuilder reverseOriginalCode = new StringBuilder(originalCode).reverse();
- StringBuilder reverseSynthCode = new StringBuilder(synthCode).reverse();
- int lastCommonPosition = findLastCommonPosition(reverseOriginalCode, reverseSynthCode,
- reverseOriginalCode.length() - originalLimit - 1,
- reverseSynthCode.length() - synthLimit - 1);
-
- if (lastCommonPosition < 0 || lastCommonPosition >= originalCode.length()) {
- return -1;
- }
-
- return originalCode.length() - lastCommonPosition - 1;
- }
-
- private int calcFirstPositionOfCommonEndInSynthCode(int synthLimit, int originalLimit) {
- StringBuilder reverseOriginalCode = new StringBuilder(originalCode).reverse();
- StringBuilder reverseSynthCode = new StringBuilder(synthCode).reverse();
-
- int lastCommonPosition = findLastCommonPosition(reverseSynthCode, reverseOriginalCode,
- reverseSynthCode.length() - synthLimit - 1,
- reverseOriginalCode.length() - originalLimit - 1);
-
- if (lastCommonPosition < 0 || lastCommonPosition >= synthCode.length()) {
- return -1;
- }
-
- return synthCode.length() - lastCommonPosition - 1;
- }
-
- private int findLastCommonPosition(StringBuilder first, StringBuilder second) {
- return findLastCommonPosition(first, second, first.length(), second.length());
- }
-
- private int findLastCommonPosition(StringBuilder first, StringBuilder second, int firstLimit,
- int secondLimit) {
- int firstIndex = -1;
- int secondIndex = -1;
- int lastCommonIndex = -1;
-
- do {
- lastCommonIndex = firstIndex;
- firstIndex = nextInterrestingPosition(first, firstIndex);
- secondIndex = nextInterrestingPosition(second, secondIndex);
- } while (firstIndex > -1 && firstIndex <= firstLimit && secondIndex > -1 &&
- secondIndex <= secondLimit && first.charAt(firstIndex) == second.charAt(secondIndex));
- return lastCommonIndex;
- }
-
- private int nextInterrestingPosition(StringBuilder code, int position) {
- do {
- position++;
- if (position >= code.length()) {
- return -1;
- }
- } while (isUninterresting(code, position));
- return position;
- }
-
- private boolean isUninterresting(StringBuilder code, int position) {
- switch (code.charAt(position)) {
- case ' ':
- case '\n':
- case '\r':
- case '\t':
+ private boolean requiresRewrite(IASTNode node) {
+ if (!getModifications(node, ModificationKind.REPLACE).isEmpty())
+ return true;
+ for (ASTModification modification : getModifications(node, ModificationKind.APPEND_CHILD)) {
+ if (!isAppendable(modification))
return true;
-
- default:
- return false;
- }
- }
-
- protected void createChange(MultiTextEdit edit, IASTNode changedNode) {
- int changeOffset = getOffsetIncludingComments(changedNode);
- createChange(edit, changeOffset);
- }
-
- private void createChange(MultiTextEdit edit, int changeOffset) {
- int i = (firstCommonInSynthEnd >= 0 ?
- firstCommonInOriginalEnd : originalCode.length()) - lastCommonInOriginalStart;
- if (i <= 0) {
- String insertCode = synthCode.substring(lastCommonInSynthStart,
- firstCommonInSynthEnd);
- InsertEdit iEdit = new InsertEdit(changeOffset + lastCommonInOriginalStart,
- insertCode);
- edit.addChild(iEdit);
- } else if ((firstCommonInSynthEnd >= 0 ?
- firstCommonInSynthEnd : synthCode.length()) - lastCommonInSynthStart <= 0) {
- int correction = 0;
- if (lastCommonInSynthStart > firstCommonInSynthEnd) {
- correction = lastCommonInSynthStart - firstCommonInSynthEnd;
- }
- DeleteEdit dEdit = new DeleteEdit(changeOffset + lastCommonInOriginalStart,
- firstCommonInOriginalEnd - lastCommonInOriginalStart + correction);
- edit.addChild(dEdit);
- } else {
- String replacementCode = getReplacementCode(lastCommonInSynthStart,
- firstCommonInSynthEnd);
- ReplaceEdit rEdit = new ReplaceEdit(
- changeOffset + Math.max(lastCommonInOriginalStart, 0),
- (firstCommonInOriginalEnd >= 0 ?
- firstCommonInOriginalEnd :
- originalCode.length()) - Math.max(lastCommonInOriginalStart, 0),
- replacementCode);
- edit.addChild(rEdit);
- }
}
+ return false;
+ }
- private String getReplacementCode(int lastCommonPositionInSynth, int firstOfCommonEndInSynth) {
- int replacementStart = Math.max(lastCommonPositionInSynth, 0);
- int replacementEnd = firstOfCommonEndInSynth >= 0 ?
- firstOfCommonEndInSynth : synthCode.length();
- if (replacementStart < replacementEnd) {
- return synthCode.substring(replacementStart, replacementEnd);
- }
- return ""; //$NON-NLS-1$
- }
+ private boolean isAppendable(ASTModification modification) {
+ if (modification.getKind() != ModificationKind.APPEND_CHILD)
+ return false;
+ IASTNode node = modification.getNewNode();
+ return node instanceof IASTDeclaration || node instanceof IASTStatement;
}
public Change getChange() {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGeneratorWriterVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGeneratorWriterVisitor.java
index 72537365b5d..7fd8a078166 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGeneratorWriterVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/changegenerator/ChangeGeneratorWriterVisitor.java
@@ -23,6 +23,7 @@ import org.eclipse.cdt.core.dom.ast.IASTInitializer;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
+import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
@@ -43,7 +44,6 @@ import org.eclipse.cdt.internal.core.dom.rewrite.commenthandler.NodeCommentMap;
* @author Emanuel Graf IFS
*/
public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
- private static final String DEFAULT_INDENTATION = ""; //$NON-NLS-1$
private final ASTModificationStore modificationStore;
private final String fileScope;
private ModificationScopeStack stack;
@@ -56,30 +56,31 @@ public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
this.fileScope = fileScope;
this.stack = new ModificationScopeStack(modificationStore);
- shouldVisitExpressions = delegateVisitor.shouldVisitExpressions;
- shouldVisitStatements = delegateVisitor.shouldVisitStatements;
- shouldVisitNames = delegateVisitor.shouldVisitNames;
+ shouldVisitArrayModifiers= delegateVisitor.shouldVisitArrayModifiers;
+ shouldVisitBaseSpecifiers = delegateVisitor.shouldVisitBaseSpecifiers;
shouldVisitDeclarations = delegateVisitor.shouldVisitDeclarators;
- shouldVisitDeclSpecifiers = delegateVisitor.shouldVisitDeclSpecifiers;
shouldVisitDeclarators = delegateVisitor.shouldVisitDeclarators;
+ shouldVisitDeclSpecifiers = delegateVisitor.shouldVisitDeclSpecifiers;
+ shouldVisitExpressions = delegateVisitor.shouldVisitExpressions;
shouldVisitInitializers = delegateVisitor.shouldVisitInitializers;
- shouldVisitBaseSpecifiers = delegateVisitor.shouldVisitBaseSpecifiers;
+ shouldVisitNames = delegateVisitor.shouldVisitNames;
shouldVisitNamespaces = delegateVisitor.shouldVisitNamespaces;
- shouldVisitTemplateParameters = delegateVisitor.shouldVisitTemplateParameters;
shouldVisitParameterDeclarations = delegateVisitor.shouldVisitParameterDeclarations;
- shouldVisitTranslationUnit = delegateVisitor.shouldVisitTranslationUnit;
+ shouldVisitPointerOperators= delegateVisitor.shouldVisitPointerOperators;
shouldVisitProblems = delegateVisitor.shouldVisitProblems;
+ shouldVisitStatements = delegateVisitor.shouldVisitStatements;
+ shouldVisitTemplateParameters = delegateVisitor.shouldVisitTemplateParameters;
+ shouldVisitTranslationUnit = delegateVisitor.shouldVisitTranslationUnit;
shouldVisitTypeIds = delegateVisitor.shouldVisitTypeIds;
- shouldVisitArrayModifiers= delegateVisitor.shouldVisitArrayModifiers;
}
public ChangeGeneratorWriterVisitor(ASTModificationStore modStore, NodeCommentMap nodeMap) {
- this(modStore, DEFAULT_INDENTATION, null, nodeMap);
+ this(modStore, null, nodeMap);
}
- public ChangeGeneratorWriterVisitor(ASTModificationStore modStore, String givenIndentation,
- String fileScope, NodeCommentMap commentMap) {
- super(givenIndentation, commentMap);
+ public ChangeGeneratorWriterVisitor(ASTModificationStore modStore, String fileScope,
+ NodeCommentMap commentMap) {
+ super(commentMap);
this.modificationStore = modStore;
this.fileScope = fileScope;
this.shouldVisitTranslationUnit = true;
@@ -210,6 +211,12 @@ public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
}
@Override
+ public int leave(IASTPointerOperator pointerOperator) {
+ super.leave(pointerOperator);
+ return PROCESS_SKIP;
+ }
+
+ @Override
public int leave(IASTProblem problem) {
super.leave(problem);
return PROCESS_SKIP;
@@ -306,6 +313,14 @@ public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
}
@Override
+ public int visit(IASTPointerOperator pointerOperator) {
+ if (doBeforeEveryNode(pointerOperator) == PROCESS_CONTINUE) {
+ return super.visit(pointerOperator);
+ }
+ return PROCESS_SKIP;
+ }
+
+ @Override
public int visit(IASTProblem problem) {
if (doBeforeEveryNode(problem) == PROCESS_CONTINUE) {
return super.visit(problem);
@@ -369,10 +384,8 @@ public class ChangeGeneratorWriterVisitor extends ASTWriterVisitor {
stack.pushScope(node);
currentMod.getNewNode().accept(this);
stack.popScope(node);
- return PROCESS_SKIP;
- } else {
- return PROCESS_SKIP;
}
+ return PROCESS_SKIP;
}
}
}
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 25620836f9d..d6defc940b4 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
@@ -13,6 +13,7 @@ package org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.TreeMap;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
@@ -171,26 +172,25 @@ public class ASTCommenter {
* @return NodeCommentMap
*/
public static NodeCommentMap getCommentedNodeMap(IASTTranslationUnit transUnit){
- if (transUnit== null) {
+ if (transUnit == null) {
return new NodeCommentMap();
}
- ArrayList<IASTComment> comments = removeNotNeededComments(transUnit);
- if (comments == null || comments.size() == 0) {
+ List<IASTComment> comments = removeNotNeededComments(transUnit);
+ if (comments == null || comments.isEmpty()) {
return new NodeCommentMap();
}
return addCommentsToCommentMap(transUnit, comments);
}
- private static ArrayList<IASTComment> removeNotNeededComments(IASTTranslationUnit transUnit) {
- ArrayList<IASTComment> comments = getCommentsInWorkspace(transUnit);
- if (comments == null || comments.size() == 0) {
+ private static List<IASTComment> removeNotNeededComments(IASTTranslationUnit transUnit) {
+ List<IASTComment> comments = getCommentsInWorkspace(transUnit);
+ if (comments == null || comments.isEmpty()) {
return null;
}
- ArrayList<IASTComment> com = removeAllPreprocessorComments(transUnit, comments);
- return com;
+ return removeAllPreprocessorComments(transUnit, comments);
}
- private static ArrayList<IASTComment> getCommentsInWorkspace(IASTTranslationUnit tu) {
+ private static List<IASTComment> getCommentsInWorkspace(IASTTranslationUnit tu) {
IASTComment[] comments = tu.getComments();
ArrayList<IASTComment> commentsInWorkspace = new ArrayList<IASTComment>();
@@ -206,8 +206,8 @@ public class ASTCommenter {
return commentsInWorkspace;
}
- private static ArrayList<IASTComment> removeAllPreprocessorComments(IASTTranslationUnit tu,
- ArrayList<IASTComment> comments) {
+ private static List<IASTComment> removeAllPreprocessorComments(IASTTranslationUnit tu,
+ List<IASTComment> comments) {
IASTPreprocessorStatement[] preprocessorStatements = tu.getAllPreprocessorStatements();
TreeMap<Integer, String> treeOfPreProcessorLines = new TreeMap<Integer,String>();
TreeMap<String, ArrayList<Integer>> ppOffsetForFiles = new TreeMap<String, ArrayList<Integer>>();
@@ -286,7 +286,7 @@ public class ASTCommenter {
}
private static NodeCommentMap addCommentsToCommentMap(IASTTranslationUnit rootNode,
- ArrayList<IASTComment> comments){
+ List<IASTComment> comments){
NodeCommentMap commentMap = new NodeCommentMap();
CommentHandler commHandler = new CommentHandler(comments);
@@ -296,8 +296,8 @@ public class ASTCommenter {
ASTCommenterVisitor commenter = new ASTCommenterVisitor(commHandler, commentMap);
declarations[i].accept(commenter);
- //add remaining comments to the last declaration => Comments won't get lost
- if (i + 1 == declarations.length) {
+ // Add the remaining comments to the last declaration to prevent comment loss.
+ if (i == declarations.length - 1) {
commenter.addRemainingComments(declarations[i]);
}
}
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 6d7b1e26776..9fbd6bbf19f 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
@@ -45,17 +45,18 @@ public class ASTCommenterVisitor extends ASTVisitor {
private NodeCommenter nodeCommenter;
{
- shouldVisitExpressions = true;
- shouldVisitStatements = true;
- shouldVisitNames = true;
+ shouldVisitBaseSpecifiers = true;
shouldVisitDeclarations = true;
- shouldVisitDeclSpecifiers = true;
shouldVisitDeclarators = true;
+ shouldVisitDeclSpecifiers = true;
+ shouldVisitExpressions = true;
shouldVisitInitializers = true;
- shouldVisitBaseSpecifiers = true;
+ shouldVisitNames = true;
shouldVisitNamespaces = true;
- shouldVisitTemplateParameters = true;
shouldVisitParameterDeclarations = true;
+ shouldVisitStatements = true;
+ shouldVisitTemplateParameters = true;
+ shouldVisitTypeIds = true;
}
public ASTCommenterVisitor(CommentHandler commHandler, NodeCommentMap commentMap) {
@@ -93,6 +94,11 @@ public class ASTCommenterVisitor extends ASTVisitor {
}
@Override
+ public int visit(IASTTypeId typeId) {
+ return nodeCommenter.appendComments((ASTNode) typeId);
+ }
+
+ @Override
public int visit(IASTDeclaration declaration) {
return nodeCommenter.appendComments((ASTNode) declaration);
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/CommentHandler.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/CommentHandler.java
index 9299f42963b..9ef98352418 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/CommentHandler.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/CommentHandler.java
@@ -7,11 +7,11 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Institute for Software - initial API and implementation
+ * Institute for Software - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;
-import java.util.ArrayList;
+import java.util.List;
import org.eclipse.cdt.core.dom.ast.IASTComment;
@@ -23,10 +23,9 @@ import org.eclipse.cdt.core.dom.ast.IASTComment;
* @author Guido Zgraggen IFS
*/
public class CommentHandler {
-
- private final ArrayList<IASTComment> comments;
+ private final List<IASTComment> comments;
- public CommentHandler(ArrayList<IASTComment> comments) {
+ public CommentHandler(List<IASTComment> comments) {
super();
this.comments = comments;
}
@@ -36,7 +35,7 @@ public class CommentHandler {
}
public boolean hasMore() {
- return comments.size()>0;
+ return !comments.isEmpty();
}
public IASTComment getFirst() {
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommentMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommentMap.java
index 4f65d336710..829c2ddd4e2 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommentMap.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommentMap.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2008 Institute for Software, HSR Hochschule fuer Technik
+ * Copyright (c) 2008, 2011 Institute for Software, HSR Hochschule fuer Technik
* Rapperswil, University of applied sciences and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
@@ -7,12 +7,14 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Institute for Software - initial API and implementation
+ * Institute for Software - initial API and implementation
******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import org.eclipse.cdt.core.dom.ast.IASTComment;
import org.eclipse.cdt.core.dom.ast.IASTNode;
@@ -25,18 +27,18 @@ import org.eclipse.cdt.core.dom.ast.IASTNode;
* @author Guido Zgraggen IFS
*/
public class NodeCommentMap {
- protected final HashMap<IASTNode, ArrayList<IASTComment>> leadingMap = new HashMap<IASTNode, ArrayList<IASTComment>>();
- protected final HashMap<IASTNode, ArrayList<IASTComment>> trailingMap = new HashMap<IASTNode, ArrayList<IASTComment>>();
- protected final HashMap<IASTNode, ArrayList<IASTComment>> freestandingMap = new HashMap<IASTNode, ArrayList<IASTComment>>();
+ protected final Map<IASTNode, List<IASTComment>> leadingMap = new HashMap<IASTNode, List<IASTComment>>();
+ protected final Map<IASTNode, List<IASTComment>> trailingMap = new HashMap<IASTNode, List<IASTComment>>();
+ protected final Map<IASTNode, List<IASTComment>> freestandingMap = new HashMap<IASTNode, List<IASTComment>>();
/**
* Add a comment to the map with the trailing comments.
* @param node The node is the key.
* @param comment The comment is the value
*/
- public void addTrailingCommentToNode(IASTNode node, IASTComment comment){
- ArrayList<IASTComment> comments = trailingMap.get(node);
- if(comments == null){
+ public void addTrailingCommentToNode(IASTNode node, IASTComment comment) {
+ List<IASTComment> comments = trailingMap.get(node);
+ if (comments == null) {
comments = new ArrayList<IASTComment>();
}
comments.add(comment);
@@ -44,17 +46,15 @@ public class NodeCommentMap {
}
/**
- * Returns an ArrayList for the given node. This ArrayList contains all the comments
+ * Returns a List for the given node. This List contains all the comments
* which are assigned to this specific node. If no comments are available an empty
- * ArrayList is returned.
+ * List is returned.
* @param node The key to fetch the associated comments.
- * @return ArrayList
+ * @return List
*/
- public ArrayList<IASTComment> getTrailingCommentsForNode(IASTNode node){
- if(trailingMap.get(node) == null) {
- return new ArrayList<IASTComment>();
- }
- return trailingMap.get(node);
+ public List<IASTComment> getTrailingCommentsForNode(IASTNode node) {
+ List<IASTComment> list = trailingMap.get(node);
+ return list != null ? list : new ArrayList<IASTComment>();
}
/**
@@ -62,9 +62,9 @@ public class NodeCommentMap {
* @param node The node is the key.
* @param comment The comment is the value
*/
- public void addLeadingCommentToNode(IASTNode node, IASTComment comment){
- ArrayList<IASTComment> comments = leadingMap.get(node);
- if(comments == null){
+ public void addLeadingCommentToNode(IASTNode node, IASTComment comment) {
+ List<IASTComment> comments = leadingMap.get(node);
+ if (comments == null) {
comments = new ArrayList<IASTComment>();
}
comments.add(comment);
@@ -72,17 +72,15 @@ public class NodeCommentMap {
}
/**
- * Returns an ArrayList for the given node. This ArrayList contains all the comments
+ * Returns a List for the given node. This List contains all the comments
* which are assigned to this specific node. If no comments are available an empty
- * ArrayList is returned.
+ * List is returned.
* @param node The key to fetch the associated comments.
- * @return ArrayList
+ * @return List
*/
- public ArrayList<IASTComment> getLeadingCommentsForNode(IASTNode node){
- if(leadingMap.get(node) == null) {
- return new ArrayList<IASTComment>();
- }
- return leadingMap.get(node);
+ public List<IASTComment> getLeadingCommentsForNode(IASTNode node) {
+ List<IASTComment> list = leadingMap.get(node);
+ return list != null ? list : new ArrayList<IASTComment>();
}
/**
@@ -90,9 +88,9 @@ public class NodeCommentMap {
* @param node The node is the key.
* @param comment The comment is the value
*/
- public void addFreestandingCommentToNode(IASTNode node, IASTComment comment){
- ArrayList<IASTComment> comments = freestandingMap.get(node);
- if(comments == null){
+ public void addFreestandingCommentToNode(IASTNode node, IASTComment comment) {
+ List<IASTComment> comments = freestandingMap.get(node);
+ if (comments == null) {
comments = new ArrayList<IASTComment>();
}
comments.add(comment);
@@ -100,51 +98,50 @@ public class NodeCommentMap {
}
/**
- * Returns an ArrayList for the given node. This ArrayList contains all the comments
+ * Returns a List for the given node. This List contains all the comments
* which are assigned to this specific node. If no comments are available an empty
- * ArrayList is returned.
+ * List is returned.
* @param node The key to fetch the associated comments.
- * @return ArrayList
+ * @return List
*/
- public ArrayList<IASTComment> getFreestandingCommentsForNode(IASTNode node){
- if(freestandingMap.get(node) == null) {
- return new ArrayList<IASTComment>();
- }
- return freestandingMap.get(node);
+ public List<IASTComment> getFreestandingCommentsForNode(IASTNode node) {
+ List<IASTComment> list = freestandingMap.get(node);
+ return list != null ? list : new ArrayList<IASTComment>();
}
-
-
+
/**
- * Returns the HashMap with all leading maps. Used only for test purpose
- * @return HashMap of all leading comments
+ * Returns the Map with all leading maps. Used only for test purpose
+ * @return Map of all leading comments
*/
- public HashMap<IASTNode, ArrayList<IASTComment>> getLeadingMap() {
+ public Map<IASTNode, List<IASTComment>> getLeadingMap() {
return leadingMap;
}
+
/**
- * Returns the HashMap with all trailing maps. Used only for test purpose
- * @return HashMap of all trailing comments
+ * Returns the Map with all trailing maps. Used only for test purpose
+ * @return Map of all trailing comments
*/
- public HashMap<IASTNode, ArrayList<IASTComment>> getTrailingMap() {
+ public Map<IASTNode, List<IASTComment>> getTrailingMap() {
return trailingMap;
}
+
/**
- * Returns the HashMap with all freestanding maps. Used only for test purpose
- * @return HashMap of all freestanding comments
+ * Returns the Map with all freestanding maps. Used only for test purpose
+ * @return Map of all freestanding comments
*/
- public HashMap<IASTNode, ArrayList<IASTComment>> getFreestandingMap() {
+ public Map<IASTNode, List<IASTComment>> getFreestandingMap() {
return freestandingMap;
}
/**
- * Returns an ArrayList for the given node. This ArrayList contains all the comments
+ * Returns an List for the given node. This List contains all the comments
* which are assigned to this specific node. If no comments are available an empty
- * ArrayList is returned.
+ * List is returned.
* @param node The key to fetch the associated comments.
- * @return ArrayList
+ * @return List
*/
- public ArrayList<IASTComment> getAllCommentsForNode(IASTNode node) {
- ArrayList<IASTComment> comment = new ArrayList<IASTComment>();
+ public List<IASTComment> getAllCommentsForNode(IASTNode node) {
+ List<IASTComment> comment = new ArrayList<IASTComment>();
comment.addAll(getFreestandingCommentsForNode(node));
comment.addAll(getLeadingCommentsForNode(node));
comment.addAll(getTrailingCommentsForNode(node));
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java
index 5ae49e8f7dc..75430528969 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/rewrite/commenthandler/NodeCommenter.java
@@ -7,7 +7,7 @@
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
- * Institute for Software - initial API and implementation
+ * Institute for Software - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.rewrite.commenthandler;
@@ -39,25 +39,27 @@ import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
/**
- * The NodeCommenter contains all the logic that is needed for the ASTCommentVisitor to assign the comments
- * to the suitable node. Together with the ASTCommenterVisitor it fills all the comments with the correspondent
- * node into the NodeCommentMap.
+ * The NodeCommenter contains all the logic that is needed for the ASTCommentVisitor to assign
+ * the comments to the suitable node. Together with the ASTCommenterVisitor it fills all
+ * the comments with the correspondent node into the NodeCommentMap.
*
- * Following, a little explanation of the assignment logic. It is only a loose illustration a detailed description
- * would include a combined explanation of ASTCommenterVisitor and NodeCommenter.<br>
+ * Following, a little explanation of the assignment logic. It is only a loose illustration
+ * a detailed description would include a combined explanation of ASTCommenterVisitor and
+ * NodeCommenter.<br>
* To understand the logic we define the three types of comments:<br>
* leading comments - Comments before a statement, declaration, or definition.<br>
* trailing comments - Comments right after the AST node on the same line.<br>
* freestanding comments - Comments before a closing brace such as they occur in
* namespace-, class- and method-definitions or at the end of a file.<br>
*
- * The first comment is fetched and the position of it is compared to the position of the actual node. If
- * the position of the comment is smaller than the comment is added to the node as leading. If it is behind the node
- * but on the same line it is added as trailing. If one of these possibilities match the next comment is fetched for
- * the same check. If it doesn't match the same procedure is done for all the child nodes. After checking the sub nodes
- * the actual node is checked again if the comment is trailing. Then there is also the possibility that this comment is
- * freestanding. This is the case when the comment is not added to any child node but the position is smaller den
- * the end position of the node.
+ * The first comment is fetched and the position of it is compared to the position of the actual
+ * node. If the position of the comment is smaller than the comment is added to the node as leading.
+ * If it is behind the node but on the same line it is added as trailing. If one of these
+ * possibilities match the next comment is fetched for the same check. If it doesn't match the same
+ * procedure is done for all the child nodes. After checking the sub nodes the actual node is
+ * checked again if the comment is trailing. Then there is also the possibility that this comment is
+ * freestanding. This is the case when the comment is not added to any child node but the position
+ * is smaller than the end position of the node.
*
* @author Guido Zgraggen IFS
*/
@@ -90,7 +92,7 @@ public class NodeCommenter {
ASTNode com = (ASTNode) comment;
if (node.getFileLocation() == null) {
- //MacroExpansions have no FileLocation
+ // MacroExpansions have no FileLocation
return false;
}
@@ -111,7 +113,7 @@ public class NodeCommenter {
ASTNode com = (ASTNode) comment;
if (node.getFileLocation() == null) {
- //MacroExpansions have no Filelocation
+ // MacroExpansions have no FileLocation
return false;
}
if (OffsetHelper.getNodeEndPoint(com) <= OffsetHelper.getNodeEndPoint(node)) {
@@ -151,7 +153,7 @@ public class NodeCommenter {
try {
InputStream is = file.getContents();
- int length = OffsetHelper.getNodeOffset(com)-OffsetHelper.getNodeEndPoint(node);
+ int length = OffsetHelper.getNodeOffset(com) - OffsetHelper.getNodeEndPoint(node);
byte[] b = new byte[length];
long count = is.skip(OffsetHelper.getEndOffsetWithoutComments(node));

Back to the top