summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Ridge2013-01-30 13:39:29 (EST)
committerSergey Prigogin2013-01-30 13:41:10 (EST)
commit9e8c662a737d697067444b8699adc36a5bb08c94 (patch)
tree16a61cbe630820ee43f674d19f3921ce84230af6
parent90bdc3c39c53086d9fb09d2800eea724efac14b8 (diff)
downloadorg.eclipse.cdt-9e8c662a737d697067444b8699adc36a5bb08c94.zip
org.eclipse.cdt-9e8c662a737d697067444b8699adc36a5bb08c94.tar.gz
org.eclipse.cdt-9e8c662a737d697067444b8699adc36a5bb08c94.tar.bz2
Bug 397342 - Error calculating size of reference typerefs/changes/26/9426/4
Change-Id: I1274da6ebd14f0c1f97dce2699d62018cff57b05 Reviewed-on: https://git.eclipse.org/r/9426 Reviewed-by: Sergey Prigogin <eclipse.sprigogin@gmail.com> IP-Clean: Sergey Prigogin <eclipse.sprigogin@gmail.com> Tested-by: Sergey Prigogin <eclipse.sprigogin@gmail.com>
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java848
-rw-r--r--core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java33
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java24
3 files changed, 901 insertions, 4 deletions
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java
new file mode 100644
index 0000000..dbcaed9
--- /dev/null
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java
@@ -0,0 +1,848 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2013 IBM Corporation 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ * Markus Schorn (Wind River Systems)
+ * Andrew Ferguson (Symbian)
+ * Mike Kucera (IBM)
+ * Sergey Prigogin (Google)
+ * Nathan Ridge
+ *******************************************************************************/
+package org.eclipse.cdt.core.parser.tests.ast2;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import junit.framework.AssertionFailedError;
+
+import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
+import org.eclipse.cdt.core.dom.ast.ASTVisitor;
+import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
+import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
+import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
+import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
+import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
+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.IASTExpressionStatement;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
+import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
+import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitName;
+import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner;
+import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
+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.IASTSimpleDeclaration;
+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.IASTTypeIdExpression;
+import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
+import org.eclipse.cdt.core.dom.ast.IBinding;
+import org.eclipse.cdt.core.dom.ast.ICompositeType;
+import org.eclipse.cdt.core.dom.ast.IField;
+import org.eclipse.cdt.core.dom.ast.IFunctionType;
+import org.eclipse.cdt.core.dom.ast.IProblemBinding;
+import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.c.ICASTTypeIdInitializerExpression;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition;
+import org.eclipse.cdt.core.dom.parser.IScannerExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.c.ANSICParserExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.c.GCCParserExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.c.GCCScannerExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.c.ICParserExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.cpp.ANSICPPParserExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.cpp.GPPParserExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.cpp.GPPScannerExtensionConfiguration;
+import org.eclipse.cdt.core.dom.parser.cpp.ICPPParserExtensionConfiguration;
+import org.eclipse.cdt.core.parser.FileContent;
+import org.eclipse.cdt.core.parser.IParserLogService;
+import org.eclipse.cdt.core.parser.IScanner;
+import org.eclipse.cdt.core.parser.IScannerInfo;
+import org.eclipse.cdt.core.parser.IncludeFileContentProvider;
+import org.eclipse.cdt.core.parser.NullLogService;
+import org.eclipse.cdt.core.parser.ParserLanguage;
+import org.eclipse.cdt.core.parser.ParserMode;
+import org.eclipse.cdt.core.parser.ScannerInfo;
+import org.eclipse.cdt.core.parser.tests.ASTComparer;
+import org.eclipse.cdt.core.testplugin.CTestPlugin;
+import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
+import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
+import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
+import org.eclipse.cdt.internal.core.dom.parser.AbstractGNUSourceCodeParser;
+import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor;
+import org.eclipse.cdt.internal.core.dom.parser.c.GNUCSourceParser;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.GNUCPPSourceParser;
+import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
+import org.eclipse.cdt.internal.core.model.ASTStringUtil;
+import org.eclipse.cdt.internal.core.parser.ParserException;
+import org.eclipse.cdt.internal.core.parser.scanner.CPreprocessor;
+
+/**
+ * @author aniefer
+ */
+public class AST2BaseTest extends BaseTestCase {
+ public final static String TEST_CODE = "<testcode>";
+ protected static final IParserLogService NULL_LOG = new NullLogService();
+ protected static boolean sValidateCopy;
+
+ private static final ScannerInfo GNU_SCANNER_INFO = new ScannerInfo(getGnuMap());
+ private static final ScannerInfo SCANNER_INFO = new ScannerInfo(getStdMap());
+
+ private static Map<String, String> getGnuMap() {
+ Map<String, String> map= new HashMap<String, String>();
+ map.put("__GNUC__", "4");
+ map.put("__GNUC_MINOR__", "7");
+ map.put("__SIZEOF_SHORT__", "2");
+ map.put("__SIZEOF_INT__", "4");
+ map.put("__SIZEOF_LONG__", "8");
+ map.put("__SIZEOF_POINTER__", "8");
+ return map;
+ }
+
+ private static Map<String, String> getStdMap() {
+ Map<String, String> map= new HashMap<String, String>();
+ map.put("__SIZEOF_SHORT__", "2");
+ map.put("__SIZEOF_INT__", "4");
+ map.put("__SIZEOF_LONG__", "8");
+ map.put("__SIZEOF_POINTER__", "8");
+ return map;
+ }
+
+ public AST2BaseTest() {
+ super();
+ }
+
+ public AST2BaseTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ sValidateCopy= true;
+ super.setUp();
+ }
+
+ protected IASTTranslationUnit parse(String code, ParserLanguage lang) throws ParserException {
+ return parse(code, lang, false, true);
+ }
+
+ protected IASTTranslationUnit parse(String code, ParserLanguage lang, boolean useGNUExtensions) throws ParserException {
+ return parse(code, lang, useGNUExtensions, true);
+ }
+
+ protected IASTTranslationUnit parse(String code, ParserLanguage lang, boolean useGNUExtensions,
+ boolean expectNoProblems) throws ParserException {
+ return parse(code, lang, useGNUExtensions, expectNoProblems, false);
+ }
+
+ protected IASTTranslationUnit parse(String code, ParserLanguage lang, boolean useGNUExtensions,
+ boolean expectNoProblems, boolean skipTrivialInitializers) throws ParserException {
+ IScanner scanner = createScanner(FileContent.create(TEST_CODE, code.toCharArray()), lang, ParserMode.COMPLETE_PARSE,
+ createScannerInfo(useGNUExtensions));
+ configureScanner(scanner);
+ AbstractGNUSourceCodeParser parser = null;
+ if (lang == ParserLanguage.CPP) {
+ ICPPParserExtensionConfiguration config = null;
+ if (useGNUExtensions) {
+ config = new GPPParserExtensionConfiguration();
+ } else {
+ config = new ANSICPPParserExtensionConfiguration();
+ }
+ parser = new GNUCPPSourceParser(scanner, ParserMode.COMPLETE_PARSE, NULL_LOG,config, null);
+ } else {
+ ICParserExtensionConfiguration config = null;
+
+ if (useGNUExtensions) {
+ config = new GCCParserExtensionConfiguration();
+ } else {
+ config = new ANSICParserExtensionConfiguration();
+ }
+
+ parser = new GNUCSourceParser(scanner, ParserMode.COMPLETE_PARSE, NULL_LOG, config, null);
+ }
+ if (skipTrivialInitializers)
+ parser.setSkipTrivialExpressionsInAggregateInitializers(true);
+
+ IASTTranslationUnit tu = parser.parse();
+ assertTrue(tu.isFrozen());
+ if (sValidateCopy)
+ validateCopy(tu);
+
+ if (parser.encounteredError() && expectNoProblems)
+ throw new ParserException("FAILURE"); //$NON-NLS-1$
+
+ if (lang == ParserLanguage.C && expectNoProblems) {
+ assertEquals(CVisitor.getProblems(tu).length, 0);
+ assertEquals(tu.getPreprocessorProblems().length, 0);
+ } else if (lang == ParserLanguage.CPP && expectNoProblems) {
+ assertEquals(CPPVisitor.getProblems(tu).length, 0);
+ assertEquals(0, tu.getPreprocessorProblems().length);
+ }
+ if (expectNoProblems)
+ assertEquals(0, tu.getPreprocessorProblems().length);
+
+ return tu;
+ }
+
+ public ScannerInfo createScannerInfo(boolean useGnu) {
+ if (useGnu)
+ return GNU_SCANNER_INFO;
+ return SCANNER_INFO;
+ }
+
+ protected void configureScanner(IScanner scanner) {
+ }
+
+ public static IScanner createScanner(FileContent codeReader, ParserLanguage lang, ParserMode mode,
+ IScannerInfo scannerInfo) {
+ IScannerExtensionConfiguration configuration = null;
+ if (lang == ParserLanguage.C) {
+ configuration= GCCScannerExtensionConfiguration.getInstance(scannerInfo);
+ } else {
+ configuration= GPPScannerExtensionConfiguration.getInstance(scannerInfo);
+ }
+ IScanner scanner;
+ scanner= new CPreprocessor(codeReader, scannerInfo, lang, NULL_LOG, configuration,
+ IncludeFileContentProvider.getSavedFilesProvider());
+ return scanner;
+ }
+
+ protected void validateSimplePostfixInitializerExpressionC(String code) throws ParserException {
+ ICASTTypeIdInitializerExpression e = (ICASTTypeIdInitializerExpression) getExpressionFromStatementInCode(code, ParserLanguage.C);
+ assertNotNull(e);
+ assertNotNull(e.getTypeId());
+ assertNotNull(e.getInitializer());
+ }
+
+ protected void validateSimpleUnaryTypeIdExpression(String code, int op) throws ParserException {
+ IASTCastExpression e = (IASTCastExpression) getExpressionFromStatementInCode(code, ParserLanguage.C);
+ assertNotNull(e);
+ assertEquals(e.getOperator(), op);
+ assertNotNull(e.getTypeId());
+ IASTIdExpression x = (IASTIdExpression) e.getOperand();
+ assertEquals(x.getName().toString(), "x"); //$NON-NLS-1$
+ }
+
+ protected void validateSimpleTypeIdExpressionC(String code, int op) throws ParserException {
+ IASTTypeIdExpression e = (IASTTypeIdExpression) getExpressionFromStatementInCode(code, ParserLanguage.C);
+ assertNotNull(e);
+ assertEquals(e.getOperator(), op);
+ assertNotNull(e.getTypeId());
+ }
+
+ protected void validateSimpleUnaryExpressionC(String code, int operator) throws ParserException {
+ IASTUnaryExpression e = (IASTUnaryExpression) getExpressionFromStatementInCode(code, ParserLanguage.C);
+ assertNotNull(e);
+ assertEquals(e.getOperator(), operator);
+ IASTIdExpression x = (IASTIdExpression) e.getOperand();
+ assertEquals(x.getName().toString(), "x"); //$NON-NLS-1$
+ }
+
+ protected void validateConditionalExpressionC(String code) throws ParserException {
+ IASTConditionalExpression e = (IASTConditionalExpression) getExpressionFromStatementInCode(code, ParserLanguage.C);
+ assertNotNull(e);
+ IASTIdExpression x = (IASTIdExpression) e.getLogicalConditionExpression();
+ assertEquals(x.getName().toString(), "x"); //$NON-NLS-1$
+ IASTIdExpression y = (IASTIdExpression) e.getPositiveResultExpression();
+ assertEquals(y.getName().toString(), "y"); //$NON-NLS-1$
+ IASTIdExpression x2 = (IASTIdExpression) e.getNegativeResultExpression();
+ assertEquals(x.getName().toString(), x2.getName().toString());
+ }
+
+ protected void validateSimpleBinaryExpressionC(String code, int operand) throws ParserException {
+ IASTBinaryExpression e = (IASTBinaryExpression) getExpressionFromStatementInCode(code, ParserLanguage.C);
+ assertNotNull(e);
+ assertEquals(e.getOperator(), operand);
+ IASTIdExpression x = (IASTIdExpression) e.getOperand1();
+ assertEquals(x.getName().toString(), "x"); //$NON-NLS-1$
+ IASTIdExpression y = (IASTIdExpression) e.getOperand2();
+ assertEquals(y.getName().toString(), "y"); //$NON-NLS-1$
+ }
+
+ protected IASTExpression getExpressionFromStatementInCode(String code, ParserLanguage language) throws ParserException {
+ StringBuffer buffer = new StringBuffer("void f() { "); //$NON-NLS-1$
+ buffer.append("int x, y;\n"); //$NON-NLS-1$
+ buffer.append(code);
+ buffer.append(";\n}"); //$NON-NLS-1$
+ IASTTranslationUnit tu = parse(buffer.toString(), language);
+ IASTFunctionDefinition f = (IASTFunctionDefinition) tu.getDeclarations()[0];
+ IASTCompoundStatement cs = (IASTCompoundStatement) f.getBody();
+ IASTExpressionStatement s = (IASTExpressionStatement) cs.getStatements()[1];
+ return s.getExpression();
+ }
+
+ protected <T extends IASTNode> T validateCopy(T tu) {
+ IASTNode copy = tu.copy();
+ assertFalse(copy.isFrozen());
+ ASTComparer.assertCopy(tu, copy);
+ return (T) copy;
+ }
+
+
+ static protected class CNameCollector extends ASTVisitor {
+ {
+ shouldVisitNames = true;
+ }
+ public List<IASTName> nameList = new ArrayList<IASTName>();
+
+ @Override
+ public int visit(IASTName name) {
+ nameList.add(name);
+ return PROCESS_CONTINUE;
+ }
+
+ public IASTName getName(int idx) {
+ if (idx < 0 || idx >= nameList.size())
+ return null;
+ return nameList.get(idx);
+ }
+
+ public int size() {
+ return nameList.size();
+ }
+ }
+
+ protected void assertInstances(CNameCollector collector, IBinding binding, int num) throws Exception {
+ int count = 0;
+
+ assertNotNull(binding);
+
+ for (int i = 0; i < collector.size(); i++) {
+ if (collector.getName(i).resolveBinding() == binding)
+ count++;
+ }
+
+ assertEquals(count, num);
+ }
+
+ static protected class CPPNameCollector extends ASTVisitor {
+ {
+ shouldVisitNames = true;
+ }
+ public List<IASTName> nameList = new ArrayList<IASTName>();
+
+ @Override
+ public int visit(IASTName name) {
+ nameList.add(name);
+ return PROCESS_CONTINUE;
+ }
+
+ public IASTName getName(int idx) {
+ if (idx < 0 || idx >= nameList.size())
+ return null;
+ return nameList.get(idx);
+ }
+
+ public int size() {
+ return nameList.size();
+ }
+
+ public void dump() {
+ for (int i= 0; i < size(); i++) {
+ IASTName name= getName(i);
+ String parent= name.getParent() != null ? name.getParent().getRawSignature() : "";
+ System.out.println(i + ": #" + name.getRawSignature() + "# " + parent);
+ }
+ }
+ }
+
+ protected void assertInstances(CPPNameCollector collector, IBinding binding, int num) throws Exception {
+ int count = 0;
+ for (int i = 0; i < collector.size(); i++) {
+ if (collector.getName(i).resolveBinding() == binding)
+ count++;
+ }
+
+ assertEquals(num, count);
+ }
+
+ protected void assertSameType(IType expected, IType actual) {
+ assertNotNull(expected);
+ assertNotNull(actual);
+ assertTrue("Expected same types, but the types were: '" +
+ ASTTypeUtil.getType(expected, false) + "' and '" + ASTTypeUtil.getType(actual, false) + "'",
+ expected.isSameType(actual));
+ }
+
+ protected void isExpressionStringEqual(IASTInitializerClause exp, String str) {
+ String expressionString = ASTStringUtil.getExpressionString((IASTExpression) exp);
+ assertEquals(str, expressionString);
+ }
+
+ protected void isExpressionStringEqual(IASTExpression exp, String str) {
+ String expressionString = ASTStringUtil.getExpressionString(exp);
+ assertEquals(str, expressionString);
+ }
+
+ protected void isParameterSignatureEqual(IASTDeclarator decltor, String str) {
+ assertTrue(decltor instanceof IASTFunctionDeclarator);
+ final String[] sigArray = ASTStringUtil.getParameterSignatureArray((IASTFunctionDeclarator) decltor);
+ assertEquals(str, "(" + ASTStringUtil.join(sigArray, ", ") + ")");
+ }
+
+ protected void isSignatureEqual(IASTDeclarator declarator, String expected) {
+ String signature= ASTStringUtil.getSignatureString(declarator);
+ assertEquals(expected, signature);
+ }
+
+ protected void isSignatureEqual(IASTDeclSpecifier declSpec, String str) {
+ assertEquals(str, ASTStringUtil.getSignatureString(declSpec, null));
+ }
+
+ protected void isSignatureEqual(IASTTypeId typeId, String str) {
+ assertEquals(str, ASTStringUtil.getSignatureString(typeId.getDeclSpecifier(), typeId.getAbstractDeclarator()));
+ }
+
+ protected void isTypeEqual(IASTDeclarator decltor, String str) {
+ assertEquals(str, ASTTypeUtil.getType(decltor));
+ }
+
+ protected void isTypeEqual(IASTTypeId typeId, String str) {
+ assertEquals(str, ASTTypeUtil.getType(typeId));
+ }
+
+ protected void isTypeEqual(IType type, String str) {
+ assertEquals(str, ASTTypeUtil.getType(type));
+ }
+
+ protected void isParameterTypeEqual(IFunctionType fType, String str) {
+ assertEquals(str, ASTTypeUtil.getParameterTypeString(fType));
+ }
+
+ static protected class CNameResolver extends ASTVisitor {
+ {
+ shouldVisitNames = true;
+ }
+ public int numProblemBindings;
+ public int numNullBindings;
+ public List<IASTName> nameList = new ArrayList<IASTName>();
+
+ @Override
+ public int visit(IASTName name) {
+ nameList.add(name);
+ IBinding binding = name.resolveBinding();
+ if (binding instanceof IProblemBinding)
+ numProblemBindings++;
+ if (binding == null)
+ numNullBindings++;
+ return PROCESS_CONTINUE;
+ }
+
+ public IASTName getName(int idx) {
+ if (idx < 0 || idx >= nameList.size())
+ return null;
+ return nameList.get(idx);
+ }
+
+ public int size() {
+ return nameList.size();
+ }
+ }
+
+ static protected class CPPNameResolver extends ASTVisitor {
+ {
+ shouldVisitNames = true;
+ }
+ public int numProblemBindings;
+ public int numNullBindings;
+ public List<IASTName> nameList = new ArrayList<IASTName>();
+
+ @Override
+ public int visit(IASTName name) {
+ nameList.add(name);
+ IBinding binding = name.resolveBinding();
+ if (binding instanceof IProblemBinding)
+ numProblemBindings++;
+ if (binding == null)
+ numNullBindings++;
+ return PROCESS_CONTINUE;
+ }
+
+ public IASTName getName(int idx) {
+ if (idx < 0 || idx >= nameList.size())
+ return null;
+ return nameList.get(idx);
+ }
+
+ public int size() {
+ return nameList.size();
+ }
+ }
+
+ protected String getAboveComment() throws IOException {
+ return getContents(1)[0].toString();
+ }
+
+ protected CharSequence[] getContents(int sections) throws IOException {
+ CTestPlugin plugin = CTestPlugin.getDefault();
+ if (plugin == null)
+ throw new AssertionFailedError("This test must be run as a JUnit plugin test");
+ return TestSourceReader.getContentsForTest(plugin.getBundle(), "parser", getClass(), getName(), sections);
+ }
+
+ protected static <T> T assertInstance(Object o, Class<T> clazz, Class... cs) {
+ assertNotNull("Expected object of " + clazz.getName() + " but got a null value", o);
+ assertTrue("Expected "+clazz.getName()+" but got "+o.getClass().getName(), clazz.isInstance(o));
+ for (Class c : cs) {
+ assertNotNull("Expected object of " + c.getName() + " but got a null value", o);
+ assertTrue("Expected " + c.getName() + " but got " + o.getClass().getName(), c.isInstance(o));
+ }
+ return clazz.cast(o);
+ }
+
+ protected static void assertField(IBinding binding, String fieldName, String ownerName) {
+ assertInstance(binding, IField.class);
+ assertEquals(fieldName, binding.getName());
+ ICompositeType struct = ((IField) binding).getCompositeTypeOwner();
+ assertEquals(ownerName, struct.getName());
+ }
+
+ protected class BindingAssertionHelper {
+ protected IASTTranslationUnit tu;
+ protected String contents;
+ protected boolean isCPP;
+
+ public BindingAssertionHelper(String contents, boolean isCPP) throws ParserException {
+ this(contents, isCPP ? ParserLanguage.CPP : ParserLanguage.C);
+ }
+
+ public BindingAssertionHelper(String contents, ParserLanguage lang) throws ParserException {
+ this.contents= contents;
+ this.isCPP= lang.isCPP();
+ this.tu= parse(contents, lang, true, false);
+ }
+
+ public IASTTranslationUnit getTranslationUnit() {
+ return tu;
+ }
+
+ public IProblemBinding assertProblem(String section, int len) {
+ if (len <= 0)
+ len= section.length() + len;
+ IBinding binding= binding(section, len);
+ assertTrue("Non-ProblemBinding for name: " + section.substring(0, len),
+ binding instanceof IProblemBinding);
+ return (IProblemBinding) binding;
+ }
+
+ public IProblemBinding assertProblem(String context, int len, int problemId) {
+ IProblemBinding problemBinding = assertProblem(context, len);
+ assertEquals(problemId, problemBinding.getID());
+ return problemBinding;
+ }
+
+ public IProblemBinding assertProblem(String context, String name) {
+ IBinding binding= binding(context, name);
+ assertTrue("Non-ProblemBinding for name: " + name, binding instanceof IProblemBinding);
+ return (IProblemBinding) binding;
+ }
+
+ public IProblemBinding assertProblem(String context, String name, int problemId) {
+ IProblemBinding problemBinding = assertProblem(context, name);
+ assertEquals(problemId, problemBinding.getID());
+ return problemBinding;
+ }
+
+ public <T extends IBinding> T assertNonProblem(String section, int len) {
+ if (len <= 0)
+ len= section.length() + len;
+ IBinding binding= binding(section, len);
+ if (binding instanceof IProblemBinding) {
+ IProblemBinding problem= (IProblemBinding) binding;
+ fail("ProblemBinding for name: " + section.substring(0, len) + " (" + renderProblemID(problem.getID()) + ")");
+ }
+ if (binding == null) {
+ fail("Null binding resolved for name: " + section.substring(0, len));
+ }
+ return (T) binding;
+ }
+
+ private int getIdentifierLength(String str) {
+ int i;
+ for (i = 0; i < str.length() && Character.isJavaIdentifierPart(str.charAt(i)); ++i) {
+ }
+ return i;
+ }
+
+ public IProblemBinding assertProblemOnFirstIdentifier(String section) {
+ return assertProblem(section, getIdentifierLength(section));
+ }
+
+ public IProblemBinding assertProblemOnFirstIdentifier(String section, int problemId) {
+ IProblemBinding problemBinding = assertProblemOnFirstIdentifier(section);
+ assertEquals(problemId, problemBinding.getID());
+ return problemBinding;
+ }
+
+ public <T extends IBinding> T assertNonProblemOnFirstIdentifier(String section, Class... cs) {
+ return assertNonProblem(section, getIdentifierLength(section), cs);
+ }
+
+ public IBinding assertNonProblemOnFirstIdentifier(String section) {
+ return assertNonProblem(section, getIdentifierLength(section), IBinding.class);
+ }
+
+ public void assertNoName(String section, int len) {
+ IASTName name= findName(section, len);
+ if (name != null) {
+ String selection = section.substring(0, len);
+ fail("Found unexpected \"" + selection + "\": " + name.resolveBinding());
+ }
+ }
+
+ /**
+ * Asserts that there is exactly one name at the given location and that
+ * it resolves to the given type of binding.
+ */
+ public IASTImplicitName assertImplicitName(String section, int len, Class<?> bindingClass) {
+ IASTName name = findImplicitName(section, len);
+ final String selection = section.substring(0, len);
+ assertNotNull("did not find \"" + selection + "\"", name);
+
+ assertInstance(name, IASTImplicitName.class);
+ IASTImplicitNameOwner owner = (IASTImplicitNameOwner) name.getParent();
+ IASTImplicitName[] implicits = owner.getImplicitNames();
+ assertNotNull(implicits);
+
+ if (implicits.length > 1) {
+ boolean found = false;
+ for (IASTImplicitName n : implicits) {
+ if (((ASTNode) n).getOffset() == ((ASTNode) name).getOffset()) {
+ assertFalse(found);
+ found = true;
+ }
+ }
+ assertTrue(found);
+ }
+
+ assertEquals(selection, name.getRawSignature());
+ IBinding binding = name.resolveBinding();
+ assertNotNull(binding);
+ assertInstance(binding, bindingClass);
+ return (IASTImplicitName) name;
+ }
+
+ public void assertNoImplicitName(String section, int len) {
+ IASTName name = findImplicitName(section, len);
+ final String selection = section.substring(0, len);
+ assertNull("found name \"" + selection + "\"", name);
+ }
+
+ public IASTImplicitName[] getImplicitNames(String section, int len) {
+ IASTName name = findImplicitName(section, len);
+ IASTImplicitNameOwner owner = (IASTImplicitNameOwner) name.getParent();
+ IASTImplicitName[] implicits = owner.getImplicitNames();
+ return implicits;
+ }
+
+ public IASTName findName(String section, int len) {
+ final int offset = contents.indexOf(section);
+ assertTrue("Section \"" + section + "\" not found", offset >= 0);
+ IASTNodeSelector selector = tu.getNodeSelector(null);
+ return selector.findName(offset, len);
+ }
+
+ public IASTName findName(String context, String name) {
+ if (context == null) {
+ context = contents;
+ }
+ int offset = contents.indexOf(context);
+ assertTrue("Context \"" + context + "\" not found", offset >= 0);
+ int nameOffset = context.indexOf(name);
+ assertTrue("Name \"" + name + "\" not found", nameOffset >= 0);
+ IASTNodeSelector selector = tu.getNodeSelector(null);
+ return selector.findName(offset + nameOffset, name.length());
+ }
+
+ public IASTName findName(String name) {
+ return findName(contents, name);
+ }
+
+ public IASTName findImplicitName(String section, int len) {
+ final int offset = contents.indexOf(section);
+ assertTrue(offset >= 0);
+ IASTNodeSelector selector = tu.getNodeSelector(null);
+ return selector.findImplicitName(offset, len);
+ }
+
+ public <T extends IASTNode> T assertNode(String context, String nodeText, Class... cs) {
+ if (context == null) {
+ context = contents;
+ }
+ int offset = contents.indexOf(context);
+ assertTrue("Context \"" + context + "\" not found", offset >= 0);
+ int nodeOffset = context.indexOf(nodeText);
+ assertTrue("Node \"" + nodeText + "\" not found", nodeOffset >= 0);
+ IASTNodeSelector selector = tu.getNodeSelector(null);
+ IASTNode node = selector.findNode(offset + nodeOffset, nodeText.length());
+ return assertType(node, cs);
+ }
+
+ public <T extends IASTNode> T assertNode(String nodeText, Class... cs) {
+ return assertNode(contents, nodeText, cs);
+ }
+
+ private String renderProblemID(int i) {
+ try {
+ for (Field field : IProblemBinding.class.getDeclaredFields()) {
+ if (field.getName().startsWith("SEMANTIC_")) {
+ if (field.getType() == int.class) {
+ Integer ci= (Integer) field.get(null);
+ if (ci.intValue() == i) {
+ return field.getName();
+ }
+ }
+ }
+ }
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ return "Unknown problem ID";
+ }
+
+ public <T extends IBinding> T assertNonProblem(String section, int len, Class... cs) {
+ if (len <= 0)
+ len += section.length();
+ IBinding binding= binding(section, len);
+ assertTrue("ProblemBinding for name: " + section.substring(0, len),
+ !(binding instanceof IProblemBinding));
+ return assertType(binding, cs);
+ }
+
+ public <T extends IBinding> T assertNonProblem(String section, Class... cs) {
+ return assertNonProblem(section, section.length(), cs);
+ }
+
+ public <T extends IBinding> T assertNonProblem(String context, String name, Class... cs) {
+ IBinding binding= binding(context, name);
+ assertTrue("ProblemBinding for name: " + name, !(binding instanceof IProblemBinding));
+ return assertType(binding, cs);
+ }
+
+ public <T, U extends T> U assertType(T obj, Class... cs) {
+ for (Class c : cs) {
+ assertInstance(obj, c);
+ }
+ return (U) obj;
+ }
+
+ private IBinding binding(String section, int len) {
+ IASTName astName = findName(section, len);
+ final String selection = section.substring(0, len);
+ assertNotNull("No AST name for \"" + selection + "\"", astName);
+ assertEquals(selection, astName.getRawSignature());
+
+ IBinding binding = astName.resolveBinding();
+ assertNotNull("No binding for " + astName.getRawSignature(), binding);
+
+ return astName.resolveBinding();
+ }
+
+ private IBinding binding(String context, String name) {
+ IASTName astName = findName(context, name);
+ assertNotNull("No AST name for \"" + name + "\"", astName);
+ assertEquals(name, astName.getRawSignature());
+
+ IBinding binding = astName.resolveBinding();
+ assertNotNull("No binding for " + astName.getRawSignature(), binding);
+
+ return astName.resolveBinding();
+ }
+ }
+
+ final protected IASTTranslationUnit parseAndCheckBindings(String code, ParserLanguage lang) throws Exception {
+ return parseAndCheckBindings(code, lang, false);
+ }
+
+ final protected IASTTranslationUnit parseAndCheckBindings(String code, ParserLanguage lang, boolean useGnuExtensions) throws Exception {
+ return parseAndCheckBindings(code, lang, useGnuExtensions, false);
+ }
+
+ final protected IASTTranslationUnit parseAndCheckBindings(String code, ParserLanguage lang, boolean useGnuExtensions,
+ boolean skipTrivialInitializers) throws Exception {
+ IASTTranslationUnit tu = parse(code, lang, useGnuExtensions, true, skipTrivialInitializers);
+ CNameCollector col = new CNameCollector();
+ tu.accept(col);
+ assertNoProblemBindings(col);
+ return tu;
+ }
+
+ final protected void assertNoProblemBindings(CNameCollector col) {
+ for (IASTName n : col.nameList) {
+ assertFalse("ProblemBinding for " + n.getRawSignature(), n.resolveBinding() instanceof IProblemBinding);
+ }
+ }
+
+ final protected void assertProblemBindings(CNameCollector col, int count) {
+ int sum = 0;
+ for (IASTName n : col.nameList) {
+ if (n.getBinding() instanceof IProblemBinding)
+ ++sum;
+ }
+ assertEquals(count, sum);
+ }
+
+ final protected <T extends IASTDeclaration> T getDeclaration(IASTTranslationUnit tu, int i_decl) {
+ Class<T> tclass;
+ IASTDeclaration[] decls= tu.getDeclarations();
+ assertTrue(decls.length > i_decl);
+ return (T) decls[i_decl];
+ }
+
+ final protected <T extends IASTDeclaration> T getDeclaration(ICPPASTNamespaceDefinition ns, int i_decl) {
+ Class<T> tclass;
+ IASTDeclaration[] decls= ns.getDeclarations();
+ assertTrue(decls.length > i_decl);
+ return (T) decls[i_decl];
+ }
+
+ final protected <T extends IASTDeclaration> T getDeclaration(ICPPASTLinkageSpecification ls, int i_decl) {
+ Class<T> tclass;
+ IASTDeclaration[] decls= ls.getDeclarations();
+ assertTrue(decls.length > i_decl);
+ return (T) decls[i_decl];
+ }
+
+ final protected <T extends IASTDeclaration> T getDeclaration(IASTCompositeTypeSpecifier ct, int i_decl) {
+ Class<T> tclass;
+ IASTDeclaration[] decls= ct.getMembers();
+ assertTrue(decls.length > i_decl);
+ return (T) decls[i_decl];
+ }
+
+ final protected <T extends IASTCompositeTypeSpecifier> T getCompositeType(IASTTranslationUnit tu, int i_decl) {
+ IASTSimpleDeclaration sdecl= getDeclaration(tu, i_decl);
+ return (T) sdecl.getDeclSpecifier();
+ }
+
+ final protected <T extends IASTStatement> T getStatement(IASTFunctionDefinition fdef, int i_stmt) {
+ return getStatement((IASTCompoundStatement) fdef.getBody(), i_stmt);
+ }
+
+ final protected <T extends IASTStatement> T getStatement(IASTCompoundStatement compound, int i_stmt) {
+ IASTStatement[] stmts= compound.getStatements();
+ assertTrue(stmts.length > i_stmt);
+ return (T) stmts[i_stmt];
+ }
+
+ final protected <T extends IASTExpression> T getExpressionOfStatement(IASTFunctionDefinition fdef, int i) {
+ IASTStatement stmt= getStatement(fdef, i);
+ assertInstance(stmt, IASTExpressionStatement.class);
+ return (T) ((IASTExpressionStatement) stmt).getExpression();
+ }
+}
diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
index eb4b961..ff1f4ee 100644
--- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
+++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java
@@ -128,6 +128,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.parser.ParserLanguage;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
+import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClassType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPMethod;
@@ -10153,4 +10154,36 @@ public class AST2CPPTests extends AST2TestBase {
public void testIsBaseOf_399353() throws Exception {
parseAndCheckBindings(getAboveComment(), CPP, true);
}
+
+ // template <bool> struct B{};
+ // template <>
+ // struct B<true> {
+ // void waldo();
+ // };
+ // typedef char& one;
+ // int main() {
+ // B<sizeof(one) == 1> b;
+ // b.waldo();
+ // }
+ public void testSizeofReference_397342() throws Exception {
+ parseAndCheckBindings();
+ }
+
+ // struct A {
+ // char a[100];
+ // };
+ // struct B {
+ // A& b;
+ // };
+ // A* p;
+ public void testSizeofStructWithReferenceField_397342() throws Exception {
+ BindingAssertionHelper bh = getAssertionHelper();
+ IASTName nameB = bh.findName("B");
+ IASTName namep = bh.findName("p");
+ ICPPClassType B = (ICPPClassType) nameB.resolveBinding();
+ IPointerType ptrToA = (IPointerType) ((ICPPVariable) namep.resolveBinding()).getType();
+ long pointerSize = SizeofCalculator.getSizeAndAlignment(ptrToA, namep).size;
+ long BSize = SizeofCalculator.getSizeAndAlignment(B, nameB).size;
+ assertEquals(pointerSize, BSize);
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java
index 92ebd31..387da41 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/SizeofCalculator.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2011 Google, Inc and others.
+ * Copyright (c) 2011, 2013 Google, 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:
* Sergey Prigogin (Google) - initial API and implementation
+ * Nathan Ridge
*******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;
@@ -182,7 +183,12 @@ public class SizeofCalculator {
if (type instanceof IBasicType) {
return sizeAndAlignment((IBasicType) type);
}
- if (type instanceof IPointerType || type instanceof ICPPReferenceType) {
+ // [expr.sizeof]/2: "When applied to a reference or a reference type, the
+ // result is the size of the referenced type."
+ if (type instanceof ICPPReferenceType) {
+ return sizeAndAlignment(((ICPPReferenceType) type).getType());
+ }
+ if (type instanceof IPointerType) {
if (type instanceof ICPPPointerToMemberType)
return null;
return sizeof_pointer;
@@ -314,14 +320,24 @@ public class SizeofCalculator {
if (field.isStatic())
continue;
IType fieldType = field.getType();
- SizeAndAlignment info = sizeAndAlignment(fieldType);
+ SizeAndAlignment info;
+ // sizeof() on a reference type returns the size of the referenced type.
+ // However, a reference field in a structure only occupies as much space
+ // as a pointer.
+ if (fieldType instanceof ICPPReferenceType) {
+ info = sizeof_pointer;
+ } else {
+ info = sizeAndAlignment(fieldType);
+ }
if (info == null)
return null;
if (union) {
if (size < info.size)
size = info.size;
} else {
- size += info.alignment - (size - 1) % info.alignment - 1 + info.size;
+ if (size > 0)
+ size += info.alignment - (size - 1) % info.alignment - 1;
+ size += info.size;
}
if (maxAlignment < info.alignment)
maxAlignment = info.alignment;