diff options
9 files changed, 474 insertions, 29 deletions
diff --git a/core/org.eclipse.cdt.core.tests/META-INF/MANIFEST.MF b/core/org.eclipse.cdt.core.tests/META-INF/MANIFEST.MF index 4440d94a580..21c06c6e5bd 100644 --- a/core/org.eclipse.cdt.core.tests/META-INF/MANIFEST.MF +++ b/core/org.eclipse.cdt.core.tests/META-INF/MANIFEST.MF @@ -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 diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ChangeGeneratorTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ChangeGeneratorTest.java index b47cde43839..27bb0a69004 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ChangeGeneratorTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ChangeGeneratorTest.java @@ -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); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/CopyReplaceVisitor.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/CopyReplaceVisitor.java new file mode 100644 index 00000000000..476ab09f985 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/CopyReplaceVisitor.java @@ -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); + } +}
\ No newline at end of file diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ProblemNodeChecker.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ProblemNodeChecker.java new file mode 100644 index 00000000000..b5d40613e27 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ProblemNodeChecker.java @@ -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; + } +} diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ReplaceTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ReplaceTests.java index 0a477475d42..c92f2e66053 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ReplaceTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/rewrite/changegenerator/ReplaceTests.java @@ -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)); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java index dce940df4d9..3aa419d89e2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/AbstractGNUSourceCodeParser.java @@ -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); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index 7d5aeac2c05..42a77d8fba0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -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); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java index b0404798d45..4337d5f9f30 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/GNUCPPSourceParser.java @@ -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 { diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java index 7831a61b246..3bb46f31da8 100644 --- a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java +++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/formatter/CodeFormatterVisitor.java @@ -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(); } |