mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-31 04:45:38 +02:00
Bug 533552: Rewriting nodes with attributes causes attribute duplication
Fix and tests. Also fixes bug 535265, since the Codan Quickfix tests fail otherwise. Change-Id: Id31e40907b7ebdeee4a67c014c3a1b1cd37579ad Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch> Signed-off-by: Thomas Corbat <tcorbat@hsr.ch>
This commit is contained in:
parent
75e8ed9fc5
commit
2ca147ebf1
9 changed files with 474 additions and 29 deletions
|
@ -40,7 +40,8 @@ Require-Bundle: org.eclipse.core.resources,
|
|||
org.eclipse.ui,
|
||||
org.eclipse.jface.text,
|
||||
org.eclipse.core.filesystem,
|
||||
org.eclipse.ltk.core.refactoring;bundle-version="3.4.0"
|
||||
org.eclipse.ltk.core.refactoring;bundle-version="3.4.0",
|
||||
org.hamcrest
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Bundle-Vendor: Eclipse CDT
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
|
|
|
@ -11,6 +11,9 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.parser.tests.rewrite.changegenerator;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
|
@ -71,9 +74,24 @@ public abstract class ChangeGeneratorTest extends BaseTestFramework {
|
|||
}
|
||||
|
||||
protected void compareResult(ASTVisitor visitor) throws Exception {
|
||||
compareResult(visitor, false);
|
||||
}
|
||||
|
||||
protected void compareResult(ASTVisitor visitor, boolean shouldValidateAST) throws Exception {
|
||||
final StringBuilder[] testSources = getTestSource(2);
|
||||
final String source = testSources[0].toString();
|
||||
final String expected = testSources[1].toString();
|
||||
compareResult(visitor, testSources[0].toString(), testSources[1].toString(), shouldValidateAST);
|
||||
}
|
||||
|
||||
protected void compareCopyResult(ASTVisitor visitor) throws Exception {
|
||||
compareCopyResult(visitor, true);
|
||||
}
|
||||
|
||||
protected void compareCopyResult(ASTVisitor visitor, boolean shouldValidateAST) throws Exception {
|
||||
final StringBuilder[] testSources = getTestSource(1);
|
||||
compareResult(visitor, testSources[0].toString(), testSources[0].toString(), shouldValidateAST);
|
||||
}
|
||||
|
||||
private void compareResult(ASTVisitor visitor, String source, String expected, boolean shouldValidateAST) throws Exception {
|
||||
final IFile testFile = importFile("source.h", source); //$NON-NLS-1$
|
||||
|
||||
CCorePlugin.getIndexManager().reindex(cproject);
|
||||
|
@ -83,13 +101,22 @@ public abstract class ChangeGeneratorTest extends BaseTestFramework {
|
|||
waitForIndexer(cproject);
|
||||
|
||||
final IASTTranslationUnit unit = CoreModelUtil.findTranslationUnit(testFile).getAST();
|
||||
|
||||
if (shouldValidateAST) {
|
||||
ProblemNodeChecker validator = new ProblemNodeChecker();
|
||||
unit.accept(validator);
|
||||
assertFalse("Problem nodes found, AST is invalid.", validator.problemsFound());
|
||||
}
|
||||
|
||||
final ChangeGenerator changeGenerator =
|
||||
new ChangeGenerator(modStore, ASTCommenter.getCommentedNodeMap(unit));
|
||||
unit.accept(visitor);
|
||||
|
||||
changeGenerator.generateChange(unit);
|
||||
final Document doc = new Document(source);
|
||||
for (Change change : ((CompositeChange) changeGenerator.getChange()).getChildren()) {
|
||||
Change[] changes = ((CompositeChange) changeGenerator.getChange()).getChildren();
|
||||
assertThat("No changes found",changes.length, is(greaterThan(0)));
|
||||
for (Change change : changes) {
|
||||
if (change instanceof TextFileChange) {
|
||||
TextFileChange textChange = (TextFileChange) change;
|
||||
textChange.getEdit().apply(doc);
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
|
||||
* Rapperswil, University of applied sciences.
|
||||
* 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Hansruedi Patzen (IFS) - Initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.core.parser.tests.rewrite.changegenerator;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTAttribute;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTEnumerationSpecifier.IASTEnumerator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode.CopyStyle;
|
||||
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.IASTToken;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
|
||||
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCapture;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTClassVirtSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDecltypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDesignator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateParameter;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVirtSpecifier;
|
||||
import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification.ModificationKind;
|
||||
|
||||
public class CopyReplaceVisitor extends ASTVisitor {
|
||||
private ChangeGeneratorTest changeGenereatorTest;
|
||||
private Predicate<IASTNode> predicate;
|
||||
|
||||
public CopyReplaceVisitor(ChangeGeneratorTest changeGenereatorTest, Predicate<IASTNode> predicate) {
|
||||
super(true);
|
||||
this.changeGenereatorTest = changeGenereatorTest;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
private int copyReplace(IASTNode node) {
|
||||
if (predicate.test(node)) {
|
||||
changeGenereatorTest.addModification(null, ModificationKind.REPLACE, node, node.copy(CopyStyle.withLocations));
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTTranslationUnit tu) {
|
||||
return copyReplace(tu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTName name) {
|
||||
return copyReplace(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclaration declaration) {
|
||||
return copyReplace(declaration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTInitializer initializer) {
|
||||
return copyReplace(initializer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTParameterDeclaration parameterDeclaration) {
|
||||
return copyReplace(parameterDeclaration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclarator declarator) {
|
||||
return copyReplace(declarator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclSpecifier declSpec) {
|
||||
return copyReplace(declSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTArrayModifier arrayModifier) {
|
||||
return copyReplace(arrayModifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTPointerOperator ptrOperator) {
|
||||
return copyReplace(ptrOperator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTAttribute attribute) {
|
||||
return copyReplace(attribute);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTAttributeSpecifier specifier) {
|
||||
return copyReplace(specifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTToken token) {
|
||||
return copyReplace(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTExpression expression) {
|
||||
return copyReplace(expression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTStatement statement) {
|
||||
return copyReplace(statement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTTypeId typeId) {
|
||||
return copyReplace(typeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTEnumerator enumerator) {
|
||||
return copyReplace(enumerator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTProblem problem) {
|
||||
return copyReplace(problem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTBaseSpecifier baseSpecifier) {
|
||||
return copyReplace(baseSpecifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTNamespaceDefinition namespaceDefinition) {
|
||||
return copyReplace(namespaceDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTTemplateParameter templateParameter) {
|
||||
return copyReplace(templateParameter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTCapture capture) {
|
||||
return copyReplace(capture);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICASTDesignator designator) {
|
||||
return copyReplace(designator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTDesignator designator) {
|
||||
return copyReplace(designator);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTVirtSpecifier virtSpecifier) {
|
||||
return copyReplace(virtSpecifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTClassVirtSpecifier classVirtSpecifier) {
|
||||
return copyReplace(classVirtSpecifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(ICPPASTDecltypeSpecifier decltypeSpecifier) {
|
||||
return copyReplace(decltypeSpecifier);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2018 Institute for Software, HSR Hochschule fuer Technik
|
||||
* Rapperswil, University of applied sciences.
|
||||
* 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
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Institute for Software - Initial API and implementation
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.core.parser.tests.rewrite.changegenerator;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblem;
|
||||
|
||||
public class ProblemNodeChecker extends ASTVisitor {
|
||||
|
||||
private boolean problemFound = false;
|
||||
|
||||
{
|
||||
shouldVisitProblems = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTProblem problem) {
|
||||
problemFound = true;
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
|
||||
public boolean problemsFound() {
|
||||
return problemFound;
|
||||
}
|
||||
}
|
|
@ -14,11 +14,13 @@ package org.eclipse.cdt.core.parser.tests.rewrite.changegenerator;
|
|||
|
||||
import static org.eclipse.cdt.core.dom.ast.IASTLiteralExpression.lk_integer_constant;
|
||||
import static org.eclipse.cdt.internal.core.dom.rewrite.ASTModification.ModificationKind.REPLACE;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTAttribute;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTAttributeList;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
|
@ -41,9 +43,13 @@ import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTPointer;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAliasDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTAttributeList;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTBinaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
|
||||
|
@ -65,12 +71,50 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTUnaryExpression;
|
|||
import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification;
|
||||
import org.eclipse.cdt.internal.core.dom.rewrite.ASTModification.ModificationKind;
|
||||
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
public class ReplaceTests extends ChangeGeneratorTest {
|
||||
|
||||
public static TestSuite suite() {
|
||||
return new TestSuite(ReplaceTests.class);
|
||||
}
|
||||
|
||||
private IASTAttribute createAttribute(String name) {
|
||||
return factory.newAttribute(name.toCharArray(), null);
|
||||
}
|
||||
|
||||
private IASTAttributeOwner copy(IASTAttributeOwner owner) {
|
||||
return (IASTAttributeOwner) owner.copy(CopyStyle.withLocations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Attribute to an existing IASTAttributeList
|
||||
*
|
||||
* @param owner IASTAttributeOwner
|
||||
* @param attributeName Name of the new Attribute
|
||||
* @param index Index of existing IASTAttributeList
|
||||
*/
|
||||
private void addAttributeToListModification(IASTAttributeOwner owner, String attributeName, int index) {
|
||||
IASTAttributeOwner copy = copy(owner);
|
||||
IASTAttributeList attributeList = (IASTAttributeList) copy.getAttributeSpecifiers()[index];
|
||||
attributeList.addAttribute(createAttribute(attributeName));
|
||||
addModification(null, ModificationKind.REPLACE, owner, copy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Addds a new AttributeList to a IASTAttributeOwner
|
||||
*
|
||||
* @param owner IASTAttributeOwner
|
||||
* @param attributeName Name of the new Attribute
|
||||
*/
|
||||
private void addAttributeListModification(IASTAttributeOwner owner, String attributeName) {
|
||||
IASTAttributeOwner copy = copy(owner);
|
||||
ICPPASTAttributeList attributeList = factory.newAttributeList();
|
||||
attributeList.addAttribute(createAttribute(attributeName));
|
||||
copy.addAttributeSpecifier(attributeList);
|
||||
addModification(null, ModificationKind.REPLACE, owner, copy);
|
||||
}
|
||||
|
||||
//int *pi[3];
|
||||
|
||||
//int *pi[15];
|
||||
|
@ -1045,4 +1089,81 @@ public class ReplaceTests extends ChangeGeneratorTest {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
//[[foo]] int hs = 5;
|
||||
public void testCopyReplaceAttribute_Bug533552_1a() throws Exception {
|
||||
compareCopyResult(new CopyReplaceVisitor(this, IASTDeclaration.class::isInstance));
|
||||
}
|
||||
|
||||
//[[foo, bar]][[foobar]] int hs = 5;
|
||||
public void testCopyReplaceAttribute_Bug533552_1b() throws Exception {
|
||||
compareCopyResult(new CopyReplaceVisitor(this, IASTDeclaration.class::isInstance));
|
||||
}
|
||||
|
||||
//[[foo, bar]][[foobar]] int [[asdf]] hs = 5;
|
||||
public void testCopyReplaceAttribute_Bug533552_1c() throws Exception {
|
||||
compareCopyResult(new CopyReplaceVisitor(this, IASTDeclaration.class::isInstance));
|
||||
}
|
||||
|
||||
//using I [[attribute]] = int;
|
||||
public void testCopyReplaceAliasDeclarationWithAttributes_Bug533552_1d() throws Exception {
|
||||
compareCopyResult(new CopyReplaceVisitor(this, ICPPASTAliasDeclaration.class::isInstance));
|
||||
}
|
||||
|
||||
//int i [[attribute]];
|
||||
public void testCopyReplaceDeclaratorWithAttributes_Bug533552_1e() throws Exception {
|
||||
compareCopyResult(new CopyReplaceVisitor(this, IASTDeclarator.class::isInstance));
|
||||
}
|
||||
|
||||
//[[foo]] int hs = 5;
|
||||
|
||||
//[[foo, bar]] int hs = 5;
|
||||
public void testAddAttribute_Bug533552_2a() throws Exception {
|
||||
compareResult(new ASTVisitor() {
|
||||
{
|
||||
shouldVisitDeclarations = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclaration declaration) {
|
||||
if (declaration instanceof IASTSimpleDeclaration) {
|
||||
addAttributeToListModification((IASTSimpleDeclaration) declaration, "bar", 0);
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//[[foo]] int hs = 5;
|
||||
|
||||
//[[foo]][[bar]] int hs = 5;
|
||||
public void testAddAttribute_Bug533552_2b() throws Exception {
|
||||
compareResult(new ASTVisitor() {
|
||||
{
|
||||
shouldVisitDeclarations = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclaration declaration) {
|
||||
if (declaration instanceof IASTSimpleDeclaration) {
|
||||
addAttributeListModification((IASTSimpleDeclaration) declaration, "bar");
|
||||
return PROCESS_ABORT;
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//void f() {
|
||||
// switch (1) {
|
||||
// case 1:
|
||||
// [[fallthrough]];
|
||||
// case 2:
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
public void testCopyReplaceAttribute_Bug535265_1() throws Exception {
|
||||
compareCopyResult(new CopyReplaceVisitor(this, IASTSwitchStatement.class::isInstance));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1573,10 +1573,11 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
final IASTName etorName= identifier();
|
||||
final IASTEnumerator enumerator= nodeFactory.newEnumerator(etorName, null);
|
||||
endOffset= calculateEndOffset(etorName);
|
||||
setRange(enumerator, problemOffset, endOffset);
|
||||
|
||||
List<IASTAttributeSpecifier> attributes = __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers);
|
||||
addAttributeSpecifiers(attributes, enumerator);
|
||||
|
||||
List<IASTAttributeSpecifier> attributes = __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers);
|
||||
addAttributeSpecifiers(attributes, enumerator);
|
||||
endOffset = attributesEndOffset(endOffset, attributes);
|
||||
setRange(enumerator, problemOffset, endOffset);
|
||||
|
||||
result.addEnumerator(enumerator);
|
||||
if (LTcatchEOF(1) == IToken.tASSIGN) {
|
||||
|
@ -2434,7 +2435,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
return null;
|
||||
|
||||
IASTAttributeList result = nodeFactory.newGCCAttributeList();
|
||||
consume();
|
||||
final int startOffset = consume().getOffset();
|
||||
int endOffset = startOffset;
|
||||
if (LT(1) == IToken.tLPAREN) {
|
||||
consume();
|
||||
consume(IToken.tLPAREN);
|
||||
|
@ -2456,8 +2458,9 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
}
|
||||
|
||||
consumeOrEOC(IToken.tRPAREN);
|
||||
consumeOrEOC(IToken.tRPAREN);
|
||||
endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset();
|
||||
}
|
||||
setRange(result, startOffset, endOffset);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2480,8 +2483,25 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
|||
return result;
|
||||
}
|
||||
|
||||
protected void addAttributeSpecifiers(List<IASTAttributeSpecifier> specifiers, IASTAttributeOwner owner) {
|
||||
if (specifiers != null && owner != null) {
|
||||
protected final int attributesStartOffset(int startOffset, List<IASTAttributeSpecifier> specifiers) {
|
||||
if (specifiers == null || specifiers.isEmpty()) {
|
||||
return startOffset;
|
||||
}
|
||||
ASTNode firstSpecifier = (ASTNode) specifiers.get(0);
|
||||
return Math.min(startOffset, firstSpecifier.getOffset());
|
||||
}
|
||||
|
||||
protected final int attributesEndOffset(int endOffset, List<IASTAttributeSpecifier> specifiers) {
|
||||
if (specifiers == null || specifiers.isEmpty()) {
|
||||
return endOffset;
|
||||
}
|
||||
ASTNode lastSpecifier = (ASTNode) specifiers.get(specifiers.size() - 1);
|
||||
return Math.max(endOffset, calculateEndOffset(lastSpecifier));
|
||||
}
|
||||
|
||||
protected final void addAttributeSpecifiers(List<IASTAttributeSpecifier> specifiers, IASTAttributeOwner owner) {
|
||||
assert owner != null;
|
||||
if (specifiers != null) {
|
||||
for (IASTAttributeSpecifier specifier : specifiers) {
|
||||
owner.addAttributeSpecifier(specifier);
|
||||
}
|
||||
|
|
|
@ -1213,7 +1213,9 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser {
|
|||
result= buildSimpleDeclSpec(storageClass, simpleType, options, isLong, typeofExpression, offset, endOffset);
|
||||
}
|
||||
result.setAlignmentSpecifiers(ArrayUtil.trim(alignmentSpecifiers));
|
||||
addAttributeSpecifiers(attributes, result);
|
||||
addAttributeSpecifiers(attributes, result);
|
||||
endOffset = attributesEndOffset(endOffset, attributes);
|
||||
setRange(result, offset, endOffset);
|
||||
} catch (BacktrackException e) {
|
||||
if (returnToken != null) {
|
||||
backup(returnToken);
|
||||
|
|
|
@ -2241,8 +2241,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
addAttributeSpecifiers(attributes, astUD);
|
||||
|
||||
((ASTNode) astUD).setOffsetAndLength(offset, endOffset - offset);
|
||||
return astUD;
|
||||
return setRange(astUD, offset, endOffset);
|
||||
}
|
||||
|
||||
if (LT(1) == IToken.tIDENTIFIER
|
||||
|
@ -2278,8 +2277,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
ICPPASTAliasDeclaration aliasDeclaration = getNodeFactory().newAliasDeclaration(aliasName, aliasedType);
|
||||
addAttributeSpecifiers(attributes, aliasDeclaration);
|
||||
setRange(aliasDeclaration, offset, endOffset);
|
||||
return aliasDeclaration;
|
||||
|
||||
return setRange(aliasDeclaration, offset, endOffset);
|
||||
}
|
||||
|
||||
private ICPPASTUsingDeclaration usingDeclaration(final int offset) throws EndOfFileException, BacktrackException {
|
||||
|
@ -2840,7 +2839,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
if (LT(1) == IToken.tLBRACE)
|
||||
throwBacktrack(LA(1));
|
||||
|
||||
final int firstOffset= LA(1).getOffset();
|
||||
final int firstOffset= attributesStartOffset(LA(1).getOffset(), attributes);
|
||||
int endOffset= firstOffset;
|
||||
boolean insertSemi= false;
|
||||
|
||||
|
@ -3553,6 +3552,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
result= buildSimpleDeclSpec(storageClass, simpleType, options, isLong, typeofExpression, offset, endOffset);
|
||||
}
|
||||
addAttributeSpecifiers(attributes, result);
|
||||
attributesEndOffset(endOffset, attributes);
|
||||
setRange(result, offset, endOffset);
|
||||
} catch (BacktrackException e) {
|
||||
if (returnToken != null) {
|
||||
backup(returnToken);
|
||||
|
@ -4510,13 +4511,14 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
pointer.setConst(isConst);
|
||||
pointer.setVolatile(isVolatile);
|
||||
pointer.setRestrict(isRestrict);
|
||||
setRange(pointer, startOffset, endOffset);
|
||||
if (result == null) {
|
||||
result= new ArrayList<>(4);
|
||||
}
|
||||
|
||||
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
|
||||
addAttributeSpecifiers(attributes, pointer);
|
||||
endOffset = attributesEndOffset(endOffset, attributes);
|
||||
setRange(pointer, startOffset, endOffset);
|
||||
|
||||
result.add(pointer);
|
||||
}
|
||||
|
@ -4595,8 +4597,9 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
}
|
||||
|
||||
addAttributeSpecifiers(attributes, result);
|
||||
endOffset = attributesEndOffset(endOffset, attributes);
|
||||
setRange(result, startingOffset, endOffset);
|
||||
|
||||
((ASTNode) result).setOffsetAndLength(startingOffset, endOffset - startingOffset);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -4757,9 +4760,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
attributes = CollectionUtils.merge(attributes, attributeSpecifierSeq());
|
||||
addAttributeSpecifiers(attributes, fc);
|
||||
if (attributes != null && !attributes.isEmpty()) {
|
||||
endOffset = getEndOffset();
|
||||
}
|
||||
endOffset = attributesEndOffset(endOffset, attributes);
|
||||
|
||||
if (LT(1) == IToken.tARROW) {
|
||||
consume();
|
||||
|
@ -5097,27 +5098,29 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
throws EndOfFileException, BacktrackException {
|
||||
boolean allowExpression= option == DeclarationOptions.TYPEID_NEW;
|
||||
while (LT(1) == IToken.tLBRACKET) {
|
||||
int o = consume().getOffset(); // eat the '['
|
||||
int startOffset = consume().getOffset(); // eat the '['
|
||||
|
||||
IASTExpression exp = null;
|
||||
if (LT(1) != IToken.tRBRACKET && LT(1) != IToken.tEOC) {
|
||||
exp = allowExpression ? expression() : constantExpression();
|
||||
allowExpression= false;
|
||||
}
|
||||
int l;
|
||||
int endOffset;
|
||||
switch (LT(1)) {
|
||||
case IToken.tRBRACKET:
|
||||
case IToken.tEOC:
|
||||
l = consume().getEndOffset();
|
||||
endOffset = consume().getEndOffset();
|
||||
break;
|
||||
default:
|
||||
throw backtrack;
|
||||
}
|
||||
IASTArrayModifier arrayMod = getNodeFactory().newArrayModifier(exp);
|
||||
((ASTNode) arrayMod).setOffsetAndLength(o, l - o);
|
||||
|
||||
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
|
||||
addAttributeSpecifiers(attributes, arrayMod);
|
||||
endOffset = attributesEndOffset(endOffset, attributes);
|
||||
|
||||
setRange(arrayMod, startOffset, endOffset);
|
||||
|
||||
collection.add(arrayMod);
|
||||
}
|
||||
|
@ -5131,6 +5134,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
|
||||
@Override
|
||||
protected IASTStatement statement() throws EndOfFileException, BacktrackException {
|
||||
int startOffset = LA(1).getOffset();
|
||||
List<IASTAttributeSpecifier> attributes = attributeSpecifierSeq();
|
||||
|
||||
IASTStatement statement = null;
|
||||
|
@ -5193,7 +5197,9 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
|||
return parseDeclarationOrExpressionStatement(attributes);
|
||||
}
|
||||
addAttributeSpecifiers(attributes, statement);
|
||||
return statement;
|
||||
|
||||
int endOffset = calculateEndOffset(statement);
|
||||
return setRange(statement, startOffset, endOffset);
|
||||
}
|
||||
|
||||
protected IASTStatement parseTryStatement() throws EndOfFileException, BacktrackException {
|
||||
|
|
|
@ -26,6 +26,8 @@ import org.eclipse.cdt.core.dom.ast.IASTASMDeclaration;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTArrayDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTArrayModifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTAttributeOwner;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTAttributeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTBreakStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCaseStatement;
|
||||
|
@ -1532,6 +1534,40 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
|||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the attributes leading a node.
|
||||
* Same as {@code formatAttributes(owner, false, true);}
|
||||
* @param owner Node containing attributes
|
||||
*/
|
||||
private void formatLeadingAttributes(IASTAttributeOwner owner) {
|
||||
formatAttributes(owner, false, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the attributes of a given attribute owner.
|
||||
*
|
||||
* @param owner Node containing attributes
|
||||
* @param printLeadingSpace Print a space before the first attribute
|
||||
* @param printTrailingSpace Print a space after the last attribute
|
||||
*/
|
||||
private void formatAttributes(IASTAttributeOwner owner, boolean printLeadingSpace, boolean printTrailingSpace) {
|
||||
if (owner == null) {
|
||||
return;
|
||||
}
|
||||
IASTAttributeSpecifier[] attributeSpecifiers = owner.getAttributeSpecifiers();
|
||||
if (attributeSpecifiers.length > 0) {
|
||||
if (printLeadingSpace) {
|
||||
scribe.space();
|
||||
}
|
||||
for (IASTAttributeSpecifier attributeSpecifier : attributeSpecifiers) {
|
||||
formatRaw(attributeSpecifier);
|
||||
}
|
||||
if (printTrailingSpace) {
|
||||
scribe.space();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void formatPointers(IASTPointerOperator[] pointers) {
|
||||
for (IASTPointerOperator pointer : pointers) {
|
||||
if (scribe.printComment()) {
|
||||
|
@ -1634,6 +1670,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
|||
}
|
||||
|
||||
private int visit(IASTSimpleDeclaration node) {
|
||||
formatLeadingAttributes(node);
|
||||
IASTDeclSpecifier declSpec= node.getDeclSpecifier();
|
||||
declSpec.accept(this);
|
||||
final List<IASTDeclarator> declarators= Arrays.asList(node.getDeclarators());
|
||||
|
@ -3142,6 +3179,7 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
|||
|
||||
private int visit(IASTNullStatement node) {
|
||||
if (!fHasClauseInitStatement && nodeOffset(node) == getCurrentPosition()) {
|
||||
formatAttributes(node, false, false);
|
||||
scribe.printNextToken(Token.tSEMI, preferences.insert_space_before_semicolon);
|
||||
scribe.printTrailingComment();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue