mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-09 01:05:38 +02:00
Bug 535274: Allow attributes on namespace definitions
Implementation and tests. Change-Id: I0cca9dea8630ae66b005856338342b4173c48216 Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch> Signed-off-by: Thomas Corbat <tcorbat@hsr.ch>
This commit is contained in:
parent
29ed1fa6c4
commit
4c66f7c8f3
9 changed files with 98 additions and 12 deletions
|
@ -44,6 +44,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTEnumerationSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
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.ICPPASTFunctionDefinition;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTIfStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
|
||||||
|
@ -537,4 +538,22 @@ public class AST2CPPAttributeTests extends AST2TestBase {
|
||||||
IASTTranslationUnit tu = parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP, true);
|
IASTTranslationUnit tu = parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP, true);
|
||||||
checkAttributeRelations(getAttributeSpecifiers(tu), ICPPASTParameterDeclaration.class, ICPPASTSimpleDeclSpecifier.class);
|
checkAttributeRelations(getAttributeSpecifiers(tu), ICPPASTParameterDeclaration.class, ICPPASTSimpleDeclSpecifier.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//namespace [[attr]] NS {}
|
||||||
|
public void testAttributedNamedNamespace_Bug535274() throws Exception {
|
||||||
|
IASTTranslationUnit tu = parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP, true);
|
||||||
|
checkAttributeRelations(getAttributeSpecifiers(tu), ICPPASTNamespaceDefinition.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
//namespace [[attr]] {}
|
||||||
|
public void testAttributedUnnamedNamespace_Bug535274() throws Exception {
|
||||||
|
IASTTranslationUnit tu = parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP, true);
|
||||||
|
checkAttributeRelations(getAttributeSpecifiers(tu), ICPPASTNamespaceDefinition.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
//namespace NS __attribute__((__visibility__("default"))) {}
|
||||||
|
public void testGnuAndCppMixedAttributedNamedNamespace_Bug535274() throws Exception {
|
||||||
|
IASTTranslationUnit tu = parseAndCheckBindings(getAboveComment(), ParserLanguage.CPP, true);
|
||||||
|
checkAttributeRelations(getAttributeSpecifiers(tu), ICPPASTNamespaceDefinition.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,3 +178,19 @@ inline namespace InlnNS
|
||||||
void f([[attr1]] int p1, int [[attr2]] p2, [[attr3]] int p3)
|
void f([[attr1]] int p1, int [[attr2]] p2, [[attr3]] int p3)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//!Attributed anonymous namespace
|
||||||
|
//%CPP
|
||||||
|
namespace [[foo]]
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//!Mixed CPP and GNU attributes on named namespace
|
||||||
|
//%CPP GNU
|
||||||
|
namespace [[foo]] FOO __attribute__((__visibility__("default")))
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -2439,8 +2439,8 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
IASTAttributeList result = nodeFactory.newGCCAttributeList();
|
IASTAttributeList result = nodeFactory.newGCCAttributeList();
|
||||||
final int startOffset = consume().getOffset();
|
final int startOffset = LA().getOffset();
|
||||||
int endOffset = startOffset;
|
int endOffset = consume().getEndOffset();
|
||||||
if (LT(1) == IToken.tLPAREN) {
|
if (LT(1) == IToken.tLPAREN) {
|
||||||
consume();
|
consume();
|
||||||
consume(IToken.tLPAREN);
|
consume(IToken.tLPAREN);
|
||||||
|
@ -2464,8 +2464,7 @@ public abstract class AbstractGNUSourceCodeParser implements ISourceCodeParser {
|
||||||
consumeOrEOC(IToken.tRPAREN);
|
consumeOrEOC(IToken.tRPAREN);
|
||||||
endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset();
|
endOffset = consumeOrEOC(IToken.tRPAREN).getEndOffset();
|
||||||
}
|
}
|
||||||
setRange(result, startOffset, endOffset);
|
return setRange(result, startOffset, endOffset);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IASTAttribute singleAttribute() throws EndOfFileException, BacktrackException {
|
protected IASTAttribute singleAttribute() throws EndOfFileException, BacktrackException {
|
||||||
|
|
|
@ -125,6 +125,9 @@ public class CPPASTNamespaceDefinition extends CPPASTAttributeOwner implements I
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!acceptByCPPAttributeSpecifiers(action))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (fName != null && !fName.accept(action))
|
if (fName != null && !fName.accept(action))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
@ -2676,6 +2676,8 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
}
|
}
|
||||||
consume(IToken.t_namespace);
|
consume(IToken.t_namespace);
|
||||||
|
|
||||||
|
List<IASTAttributeSpecifier> attributeSpecifiers = attributeSpecifierSeq();
|
||||||
|
|
||||||
// optional name
|
// optional name
|
||||||
ICPPASTName name = null;
|
ICPPASTName name = null;
|
||||||
if (LT(1) == IToken.tIDENTIFIER) {
|
if (LT(1) == IToken.tIDENTIFIER) {
|
||||||
|
@ -2686,7 +2688,7 @@ public class GNUCPPSourceParser extends AbstractGNUSourceCodeParser {
|
||||||
}
|
}
|
||||||
|
|
||||||
// bug 195701, gcc 4.2 allows visibility attribute for namespaces.
|
// bug 195701, gcc 4.2 allows visibility attribute for namespaces.
|
||||||
List<IASTAttributeSpecifier> attributeSpecifiers = __attribute_decl_seq(true, false);
|
attributeSpecifiers = CollectionUtils.merge(attributeSpecifiers, __attribute_decl_seq(true, false));
|
||||||
|
|
||||||
if (LT(1) == IToken.tLBRACE) {
|
if (LT(1) == IToken.tLBRACE) {
|
||||||
ICPPASTNamespaceDefinition outer = null;
|
ICPPASTNamespaceDefinition outer = null;
|
||||||
|
|
|
@ -3088,4 +3088,15 @@ public class CPPVisitor extends ASTQueries {
|
||||||
ArrayUtil.reverse(operands);
|
ArrayUtil.reverse(operands);
|
||||||
return operands;
|
return operands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the given {@code namespace} definition denotes
|
||||||
|
* an anonymous namespace.
|
||||||
|
* @param namespace
|
||||||
|
* @return {@code true} if the {@code namespace} is anonymous, false otherwise
|
||||||
|
*/
|
||||||
|
public static boolean isAnonymousNamespace(ICPPASTNamespaceDefinition namespace) {
|
||||||
|
IASTName name = namespace.getName();
|
||||||
|
return name == null || name.toString().isEmpty();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,6 +207,7 @@ public class DeclarationWriter extends NodeWriter {
|
||||||
scribe.printStringSpace(Keywords.INLINE);
|
scribe.printStringSpace(Keywords.INLINE);
|
||||||
}
|
}
|
||||||
scribe.printStringSpace(Keywords.NAMESPACE);
|
scribe.printStringSpace(Keywords.NAMESPACE);
|
||||||
|
writeCPPAttributes(namespaceDefinition, EnumSet.of(SpaceLocation.AFTER));
|
||||||
namespaceDefinition.getName().accept(visitor);
|
namespaceDefinition.getName().accept(visitor);
|
||||||
writeGCCAttributes(namespaceDefinition, EnumSet.of(SpaceLocation.BEFORE));
|
writeGCCAttributes(namespaceDefinition, EnumSet.of(SpaceLocation.BEFORE));
|
||||||
if (!hasTrailingComments(namespaceDefinition.getName())) {
|
if (!hasTrailingComments(namespaceDefinition.getName())) {
|
||||||
|
|
|
@ -18,6 +18,7 @@ import java.util.Collections;
|
||||||
import java.util.EmptyStackException;
|
import java.util.EmptyStackException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||||
|
@ -104,6 +105,7 @@ import org.eclipse.cdt.core.dom.ast.c.ICASTCompositeTypeSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer;
|
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignatedInitializer;
|
||||||
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator;
|
import org.eclipse.cdt.core.dom.ast.c.ICASTDesignator;
|
||||||
import org.eclipse.cdt.core.dom.ast.c.ICASTVisitor;
|
import org.eclipse.cdt.core.dom.ast.c.ICASTVisitor;
|
||||||
|
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.ICPPASTBinaryExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCastExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler;
|
||||||
|
@ -149,6 +151,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisibilityLabel;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisitor;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisitor;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.gnu.IGCCASTAttributeList;
|
||||||
import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
|
import org.eclipse.cdt.core.dom.ast.gnu.c.ICASTKnRFunctionDeclarator;
|
||||||
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants;
|
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterConstants;
|
||||||
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterOptions;
|
import org.eclipse.cdt.core.formatter.DefaultCodeFormatterOptions;
|
||||||
|
@ -1103,7 +1106,13 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
||||||
// namespace <name>
|
// namespace <name>
|
||||||
scribe.printNextToken(Token.t_namespace, false);
|
scribe.printNextToken(Token.t_namespace, false);
|
||||||
scribe.space();
|
scribe.space();
|
||||||
node.getName().accept(this);
|
formatLeadingAttributes(node, ICPPASTAttributeList.class::isInstance);
|
||||||
|
boolean isNamedNamespace = !CPPVisitor.isAnonymousNamespace(node);
|
||||||
|
if (isNamedNamespace) {
|
||||||
|
IASTName name = node.getName();
|
||||||
|
name.accept(this);
|
||||||
|
}
|
||||||
|
formatAttributes(node, isNamedNamespace, false, IGCCASTAttributeList.class::isInstance);
|
||||||
|
|
||||||
// member declarations
|
// member declarations
|
||||||
IASTDeclaration[] memberDecls= node.getDeclarations();
|
IASTDeclaration[] memberDecls= node.getDeclarations();
|
||||||
|
@ -1537,13 +1546,22 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void formatLeadingAttributes(IASTAttributeOwner owner) {
|
||||||
|
formatAttributes(owner, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the attributes leading a node.
|
* Formats the attributes leading a node.
|
||||||
* Same as {@code formatAttributes(owner, false, true);}
|
* Same as {@code formatAttributes(owner, false, true);}
|
||||||
* @param owner Node containing attributes
|
* @param owner Node containing attributes
|
||||||
|
* @param filter Filter predicate for specifying which attributes to print
|
||||||
*/
|
*/
|
||||||
private void formatLeadingAttributes(IASTAttributeOwner owner) {
|
private void formatLeadingAttributes(IASTAttributeOwner owner, Predicate<IASTAttributeSpecifier> predicate) {
|
||||||
formatAttributes(owner, false, true);
|
formatAttributes(owner, false, true, predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void formatAttributes(IASTAttributeOwner owner, boolean printLeadingSpace, boolean printTrailingSpace) {
|
||||||
|
formatAttributes(owner, printLeadingSpace, printTrailingSpace, unsused -> true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1552,8 +1570,10 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
||||||
* @param owner Node containing attributes
|
* @param owner Node containing attributes
|
||||||
* @param printLeadingSpace Print a space before the first attribute
|
* @param printLeadingSpace Print a space before the first attribute
|
||||||
* @param printTrailingSpace Print a space after the last attribute
|
* @param printTrailingSpace Print a space after the last attribute
|
||||||
|
* @param filter Filter predicate for specifying which attributes to print
|
||||||
*/
|
*/
|
||||||
private void formatAttributes(IASTAttributeOwner owner, boolean printLeadingSpace, boolean printTrailingSpace) {
|
private void formatAttributes(IASTAttributeOwner owner, boolean printLeadingSpace,
|
||||||
|
boolean printTrailingSpace, Predicate<IASTAttributeSpecifier> filter) {
|
||||||
if (owner == null) {
|
if (owner == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1563,7 +1583,9 @@ public class CodeFormatterVisitor extends ASTVisitor implements ICPPASTVisitor,
|
||||||
scribe.space();
|
scribe.space();
|
||||||
}
|
}
|
||||||
for (IASTAttributeSpecifier attributeSpecifier : attributeSpecifiers) {
|
for (IASTAttributeSpecifier attributeSpecifier : attributeSpecifiers) {
|
||||||
formatRaw(attributeSpecifier);
|
if (filter.test(attributeSpecifier)) {
|
||||||
|
formatRaw(attributeSpecifier);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (printTrailingSpace) {
|
if (printTrailingSpace) {
|
||||||
scribe.space();
|
scribe.space();
|
||||||
|
|
|
@ -15,8 +15,6 @@ package org.eclipse.cdt.ui.tests.text;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import junit.framework.TestSuite;
|
|
||||||
|
|
||||||
import org.eclipse.jface.text.BadLocationException;
|
import org.eclipse.jface.text.BadLocationException;
|
||||||
import org.eclipse.jface.text.Document;
|
import org.eclipse.jface.text.Document;
|
||||||
import org.eclipse.jface.text.IDocument;
|
import org.eclipse.jface.text.IDocument;
|
||||||
|
@ -33,6 +31,8 @@ import org.eclipse.cdt.ui.tests.BaseUITestCase;
|
||||||
import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil;
|
import org.eclipse.cdt.internal.corext.util.CodeFormatterUtil;
|
||||||
import org.eclipse.cdt.internal.formatter.align.Alignment;
|
import org.eclipse.cdt.internal.formatter.align.Alignment;
|
||||||
|
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for the CodeFormatter.
|
* Tests for the CodeFormatter.
|
||||||
*
|
*
|
||||||
|
@ -3525,4 +3525,17 @@ public class CodeFormatterTest extends BaseUITestCase {
|
||||||
public void testAttributedGotoLabel_Bug535278_5() throws Exception {
|
public void testAttributedGotoLabel_Bug535278_5() throws Exception {
|
||||||
assertFormatterResult();
|
assertFormatterResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//namespace[[foo]]{
|
||||||
|
//}
|
||||||
|
//namespace[[foo]]NS __attribute__((__visibility__("default"))){
|
||||||
|
//}
|
||||||
|
|
||||||
|
//namespace [[foo]] {
|
||||||
|
//}
|
||||||
|
//namespace [[foo]] NS __attribute__((__visibility__("default"))) {
|
||||||
|
//}
|
||||||
|
public void testAttributedNamesapces_Bug535274() throws Exception {
|
||||||
|
assertFormatterResult();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue