blob: b69b38cefb9cba08df334e6816290ba6270af078 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2016 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 static org.eclipse.cdt.core.parser.ParserLanguage.CPP;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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.IASTImplicitDestructorName;
import org.eclipse.cdt.core.dom.ast.IASTImplicitDestructorNameOwner;
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.IValue;
import org.eclipse.cdt.core.dom.ast.IVariable;
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.CBasicType;
import org.eclipse.cdt.internal.core.dom.parser.c.CPointerType;
import org.eclipse.cdt.internal.core.dom.parser.c.CQualifierType;
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.CPPBasicType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
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;
import junit.framework.AssertionFailedError;
/**
* @author aniefer
*/
public class AST2TestBase extends BaseTestCase {
public final static String TEST_CODE = "<testcode>";
protected static final IParserLogService NULL_LOG = new NullLogService();
protected static boolean sValidateCopy;
protected static class CommonCTypes {
public static IType pointerToVoid = pointerTo(CBasicType.VOID);
public static IType pointerToConstVoid = pointerTo(constOf(CBasicType.VOID));
public static IType pointerToConstInt = pointerTo(constOf(CBasicType.INT));
public static IType pointerToVolatileInt = pointerTo(volatileOf(CBasicType.INT));
public static IType pointerToConstVolatileInt = pointerTo(constVolatileOf(CBasicType.INT));
private static IType pointerTo(IType type) {
return new CPointerType(type, 0);
}
private static IType constOf(IType type) {
return new CQualifierType(type, true, false, false);
}
private static IType volatileOf(IType type) {
return new CQualifierType(type, false, true, false);
}
private static IType constVolatileOf(IType type) {
return new CQualifierType(type, true, true, false);
}
}
protected static class CommonCPPTypes {
public static IType int_ = CPPBasicType.INT;
public static IType void_ = CPPBasicType.VOID;
public static IType constInt = constOf(int_);
public static IType pointerToInt = pointerTo(int_);
public static IType pointerToConstInt = pointerTo(constInt);
public static IType referenceToInt = referenceTo(int_);
public static IType referenceToConstInt = referenceTo(constInt);
public static IType rvalueReferenceToInt = rvalueReferenceTo(int_);
public static IType rvalueReferenceToConstInt = rvalueReferenceTo(constInt);
private static IType pointerTo(IType type) {
return new CPPPointerType(type);
}
private static IType constOf(IType type) {
return new CPPQualifierType(type, true, false);
}
private static IType referenceTo(IType type) {
return new CPPReferenceType(type, false);
}
private static IType rvalueReferenceTo(IType type) {
return new CPPReferenceType(type, true);
}
}
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<>();
map.put("__GNUC__", Integer.toString(GCC_MAJOR_VERSION_FOR_TESTS));
map.put("__GNUC_MINOR__", Integer.toString(GCC_MINOR_VERSION_FOR_TESTS));
map.put("__SIZEOF_SHORT__", "2");
map.put("__SIZEOF_INT__", "4");
map.put("__SIZEOF_LONG__", "8");
map.put("__SIZEOF_DOUBLE__", "8");
map.put("__SIZEOF_POINTER__", "8");
return map;
}
private static Map<String, String> getStdMap() {
Map<String, String> map= new HashMap<>();
map.put("__SIZEOF_SHORT__", "2");
map.put("__SIZEOF_INT__", "4");
map.put("__SIZEOF_LONG__", "8");
map.put("__SIZEOF_DOUBLE__", "8");
map.put("__SIZEOF_POINTER__", "8");
return map;
}
public AST2TestBase() {
super();
}
public AST2TestBase(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, Integer.MAX_VALUE);
}
protected IASTTranslationUnit parse(String code, ParserLanguage lang, boolean useGNUExtensions,
boolean expectNoProblems, int limitTrivialInitializers) 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);
}
parser.setMaximumTrivialExpressionsInAggregateInitializers(limitTrivialInitializers);
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 {
StringBuilder buffer = new StringBuilder("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 NameCollector extends ASTVisitor {
public NameCollector() {
this(false); // don't visit implicit names by default
}
public NameCollector(boolean shouldVisitImplicitNames) {
this.shouldVisitNames = true;
this.shouldVisitImplicitNames = shouldVisitImplicitNames;
}
public List<IASTName> 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(NameCollector 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 static 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<>();
@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<>();
@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 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 static void assertConstantValue(long expected, IVariable constant) {
IValue value = constant.getInitialValue();
assertNotNull(value);
Number numericalValue = value.numberValue();
assertNotNull(numericalValue);
assertEquals(expected, numericalValue.longValue());
}
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 getIdentifierOffset(String str) {
for (int i = 0; i < str.length(); ++i) {
if (Character.isJavaIdentifierPart(str.charAt(i)))
return i;
}
fail("Didn't find identifier in \"" + str + "\"");
return -1;
}
private int getIdentifierLength(String str, int offset) {
int i;
for (i = offset; i < str.length() && Character.isJavaIdentifierPart(str.charAt(i)); ++i) {
}
return i;
}
public IProblemBinding assertProblemOnFirstIdentifier(String section) {
int offset = getIdentifierOffset(section);
String identifier = section.substring(offset, getIdentifierLength(section, offset));
return assertProblem(section, identifier);
}
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) {
int offset = getIdentifierOffset(section);
String identifier = section.substring(offset, getIdentifierLength(section, offset));
return assertNonProblem(section, identifier, cs);
}
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) {
return getImplicitNames(section, section.length());
}
public IASTImplicitName[] getImplicitNames(String section, int len) {
IASTName name = findImplicitName(section, len);
IASTImplicitNameOwner owner = (IASTImplicitNameOwner) name.getParent();
IASTImplicitName[] implicits = owner.getImplicitNames();
return implicits;
}
public IASTImplicitDestructorName[] getImplicitDestructorNames(String section) {
return getImplicitDestructorNames(section, section.length());
}
public IASTImplicitDestructorName[] getImplicitDestructorNames(String section, int len) {
final int offset = contents.indexOf(section);
assertTrue(offset >= 0);
IASTNodeSelector selector = tu.getNodeSelector(null);
IASTNode enclosingNode = selector.findEnclosingNode(offset, len);
if (!(enclosingNode instanceof IASTImplicitDestructorNameOwner))
return IASTImplicitDestructorName.EMPTY_NAME_ARRAY;
return ((IASTImplicitDestructorNameOwner) enclosingNode).getImplicitDestructorNames();
}
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 IASTImplicitName 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 void assertVariableType(String variableName, IType expectedType) {
IVariable var = assertNonProblem(variableName);
assertSameType(expectedType, var.getType());
}
public void assertVariableValue(String variableName, long expectedValue) {
IVariable var = assertNonProblem(variableName);
BaseTestCase.assertVariableValue(var, expectedValue);
}
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, Integer.MAX_VALUE);
}
final protected IASTTranslationUnit parseAndCheckBindings(String code, ParserLanguage lang, boolean useGnuExtensions,
int limitTrivialInitializers) throws Exception {
IASTTranslationUnit tu = parse(code, lang, useGnuExtensions, true, limitTrivialInitializers);
NameCollector col = new NameCollector();
tu.accept(col);
assertNoProblemBindings(col);
return tu;
}
final protected IASTTranslationUnit parseAndCheckImplicitNameBindings() throws Exception {
IASTTranslationUnit tu = parse(getAboveComment(), CPP, false, true);
NameCollector col = new NameCollector(true /* Visit implicit names */);
tu.accept(col);
assertNoProblemBindings(col);
return tu;
}
protected BindingAssertionHelper getAssertionHelper(ParserLanguage lang) throws ParserException, IOException {
String code= getAboveComment();
return new BindingAssertionHelper(code, lang);
}
final protected void assertNoProblemBindings(NameCollector col) {
for (IASTName n : col.nameList) {
assertFalse("ProblemBinding for " + n.getRawSignature(), n.resolveBinding() instanceof IProblemBinding);
}
}
final protected void assertProblemBindings(NameCollector col, int count) {
int sum = 0;
for (IASTName n : col.nameList) {
if (n.resolveBinding() 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();
}
/**
* Sort the given array of AST names lexicographically.
*/
protected static <T extends IASTName> void sortNames(T[] names) {
Arrays.sort(names, new Comparator<IASTName>() {
@Override
public int compare(IASTName a, IASTName b) {
return a.toString().compareTo(b.toString());
}});
}
}