From 62b2b932ae06ddd162d63e23c76ef21d547cc58b Mon Sep 17 00:00:00 2001 From: Nathan Ridge Date: Wed, 30 Jan 2013 10:39:29 -0800 Subject: Bug 397342 - Error calculating size of reference type Change-Id: I1274da6ebd14f0c1f97dce2699d62018cff57b05 Reviewed-on: https://git.eclipse.org/r/9426 Reviewed-by: Sergey Prigogin IP-Clean: Sergey Prigogin Tested-by: Sergey Prigogin --- .../cdt/core/parser/tests/ast2/AST2BaseTest.java | 848 +++++++++++++++++++++ .../cdt/core/parser/tests/ast2/AST2CPPTests.java | 33 + .../internal/core/dom/parser/SizeofCalculator.java | 24 +- 3 files changed, 901 insertions(+), 4 deletions(-) create mode 100644 core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2BaseTest.java 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 00000000000..dbcaed9b143 --- /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 = ""; + 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 getGnuMap() { + Map map= new HashMap(); + 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 getStdMap() { + Map map= new HashMap(); + 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 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 nameList = new ArrayList(); + + @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 nameList = new ArrayList(); + + @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 nameList = new ArrayList(); + + @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 nameList = new ArrayList(); + + @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 assertInstance(Object o, Class 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 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 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 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 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 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 assertNonProblem(String section, Class... cs) { + return assertNonProblem(section, section.length(), cs); + } + + public 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 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 getDeclaration(IASTTranslationUnit tu, int i_decl) { + Class tclass; + IASTDeclaration[] decls= tu.getDeclarations(); + assertTrue(decls.length > i_decl); + return (T) decls[i_decl]; + } + + final protected T getDeclaration(ICPPASTNamespaceDefinition ns, int i_decl) { + Class tclass; + IASTDeclaration[] decls= ns.getDeclarations(); + assertTrue(decls.length > i_decl); + return (T) decls[i_decl]; + } + + final protected T getDeclaration(ICPPASTLinkageSpecification ls, int i_decl) { + Class tclass; + IASTDeclaration[] decls= ls.getDeclarations(); + assertTrue(decls.length > i_decl); + return (T) decls[i_decl]; + } + + final protected T getDeclaration(IASTCompositeTypeSpecifier ct, int i_decl) { + Class tclass; + IASTDeclaration[] decls= ct.getMembers(); + assertTrue(decls.length > i_decl); + return (T) decls[i_decl]; + } + + final protected T getCompositeType(IASTTranslationUnit tu, int i_decl) { + IASTSimpleDeclaration sdecl= getDeclaration(tu, i_decl); + return (T) sdecl.getDeclSpecifier(); + } + + final protected T getStatement(IASTFunctionDefinition fdef, int i_stmt) { + return getStatement((IASTCompoundStatement) fdef.getBody(), i_stmt); + } + + final protected T getStatement(IASTCompoundStatement compound, int i_stmt) { + IASTStatement[] stmts= compound.getStatements(); + assertTrue(stmts.length > i_stmt); + return (T) stmts[i_stmt]; + } + + final protected 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 7488fbb69d6..324d75b26a3 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; @@ -10116,4 +10117,36 @@ public class AST2CPPTests extends AST2TestBase { public void testIsBaseOf_399353() throws Exception { parseAndCheckBindings(getAboveComment(), CPP, true); } + + // template struct B{}; + // template <> + // struct B { + // void waldo(); + // }; + // typedef char& one; + // int main() { + // B 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 92ebd31459a..387da41ee83 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; -- cgit v1.2.3