From 12cc9fcc6abf45be6f5b07496442b8ab62843a89 Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Tue, 27 May 2008 05:40:34 +0000 Subject: [PATCH] Fixed another case of an infinite loop. This time accompanied by a memory leak. --- .../cdt/core/dom/ast/ASTTypeComparator.java | 29 +++++++ .../org/eclipse/cdt/core/dom/ast/IType.java | 9 ++- .../core/parser/util/IObjectComparator.java | 15 ++++ .../cdt/core/parser/util/ObjectMap.java | 16 +++- .../cdt/core/parser/util/ObjectTable.java | 31 ++++++-- .../parser/cpp/CPPASTFunctionDeclarator.java | 77 ++++++++----------- .../parser/cpp/CPPTypedefSpecialization.java | 7 +- .../pdom/dom/cpp/PDOMCPPClassTemplate.java | 27 ++++--- 8 files changed, 144 insertions(+), 67 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeComparator.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IObjectComparator.java diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeComparator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeComparator.java new file mode 100644 index 00000000000..94e16895e28 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeComparator.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2008 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.dom.ast; + +import org.eclipse.cdt.core.parser.util.IObjectComparator; + +public class ASTTypeComparator implements IObjectComparator { + + /** + * Returns true if the two objects are equal or represent the same type. + */ + public boolean isSame(Object o1, Object o2) { + if (o1 == o2) { + return true; + } + if (o1 instanceof IType && o2 instanceof IType) { + return ((IType) o1).isSameType((IType) o2); + } + return o1.equals(o2); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IType.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IType.java index a743ce9828a..53ca22eaef3 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IType.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IType.java @@ -6,7 +6,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * IBM - Initial API and implementation + * IBM - Initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.dom.ast; @@ -14,12 +15,14 @@ package org.eclipse.cdt.core.dom.ast; * @author Doug Schaefer */ public interface IType extends Cloneable { - public static final IType [] EMPTY_TYPE_ARRAY = new IType[0]; + public static final IType[] EMPTY_TYPE_ARRAY = new IType[0]; + public static final ASTTypeComparator TYPE_COMPARATOR = new ASTTypeComparator(); + public Object clone(); /** * is the given type the same as this type? * @param type */ - public boolean isSameType( IType type ); + public boolean isSameType(IType type); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IObjectComparator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IObjectComparator.java new file mode 100644 index 00000000000..ebb2fe09b98 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/IObjectComparator.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2008 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 + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Sergey Prigogin (Google) - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.core.parser.util; + +public interface IObjectComparator { + boolean isSame(Object o1, Object o2); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectMap.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectMap.java index 5a8a1d31532..4f33592fc2d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectMap.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectMap.java @@ -144,7 +144,21 @@ public class ObjectMap extends ObjectTable { System.arraycopy(valueTable, 0, vals, 0, vals.length); return vals; } - + + public boolean isSame(ObjectMap other, IObjectComparator comparator) { + if (!super.isSame(other, comparator)) { + return false; + } + for (int i = 0; i < keyTable.length; i++) { + Object val1 = valueTable[i]; + Object val2 = other.valueTable[i]; + if (val1 != val2 && !comparator.isSame(val1, val2)) { + return false; + } + } + return true; + } + @Override public String toString() { StringBuilder sb = new StringBuilder("{"); //$NON-NLS-1$ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectTable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectTable.java index 404e3cad3fc..7a8ae42ffa5 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectTable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/parser/util/ObjectTable.java @@ -34,7 +34,7 @@ public abstract class ObjectTable extends HashTable { @Override @SuppressWarnings("unchecked") - public Object clone(){ + public Object clone() { ObjectTable newTable = (ObjectTable) super.clone(); int size = capacity(); @@ -44,10 +44,10 @@ public abstract class ObjectTable extends HashTable { return newTable; } - public List toList(){ + public List toList() { List list = new ArrayList(size()); int size = size(); - for (int i = 0; i < size; i++){ + for (int i = 0; i < size; i++) { list.add(keyAt(i)); } return list; @@ -61,14 +61,14 @@ public abstract class ObjectTable extends HashTable { } @Override - public void clear(){ + public void clear() { super.clear(); for (int i = 0; i < keyTable.length; i++) keyTable[i] = null; } @Override - protected final int hash(int pos){ + protected final int hash(int pos) { return hash(keyTable[pos]); } @@ -111,7 +111,7 @@ public abstract class ObjectTable extends HashTable { removeEntry(i, hash); } - protected final int lookup(Object buffer){ + protected final int lookup(Object buffer) { if (hashTable != null) { int hash = hash(buffer); @@ -137,11 +137,11 @@ public abstract class ObjectTable extends HashTable { return -1; } - public boolean containsKey(T key){ + public boolean containsKey(T key) { return lookup(key) != -1; } - public Object[] keyArray(){ + public Object[] keyArray() { Object[] keys = new Object[size()]; System.arraycopy(keyTable, 0, keys, 0, keys.length); return keys; @@ -153,4 +153,19 @@ public abstract class ObjectTable extends HashTable { System.arraycopy(keyTable, 0, keys, 0, keys.length); return keys; } + + public boolean isSame(ObjectTable other, IObjectComparator comparator) { + if (size() != other.size()) { + return false; + } + + for (int i = 0; i < keyTable.length; i++) { + T key1 = keyTable[i]; + T key2 = other.keyTable[i]; + if (key1 != key2 && !comparator.isSame(key1, key2)) { + return false; + } + } + return true; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java index 620b1d2947e..2aad0b00be8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTFunctionDeclarator.java @@ -27,16 +27,18 @@ import org.eclipse.cdt.core.parser.util.ArrayUtil; * @author jcamelon */ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPASTFunctionDeclarator { - - private IASTParameterDeclaration [] parameters = null; - private int parametersPos=-1; + private IASTParameterDeclaration[] parameters = null; + private int parametersPos = -1; private ICPPFunctionScope scope = null; private boolean varArgs; private boolean pureVirtual; private boolean isVolatile; private boolean isConst; - - + private IASTTypeId[] typeIds = null; + private int typeIdsPos = -1; + private ICPPASTConstructorChainInitializer[] constructorChain = null; + private int constructorChainPos = -1; + public CPPASTFunctionDeclarator() { } @@ -44,9 +46,9 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS super(name); } - public IASTParameterDeclaration [] getParameters() { - if( parameters == null ) return IASTParameterDeclaration.EMPTY_PARAMETERDECLARATION_ARRAY; - parameters = (IASTParameterDeclaration[]) ArrayUtil.removeNullsAfter( IASTParameterDeclaration.class, parameters, parametersPos ); + public IASTParameterDeclaration[] getParameters() { + if (parameters == null) return IASTParameterDeclaration.EMPTY_PARAMETERDECLARATION_ARRAY; + parameters = (IASTParameterDeclaration[]) ArrayUtil.removeNullsAfter(IASTParameterDeclaration.class, parameters, parametersPos); return parameters; } @@ -54,7 +56,7 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS if (parameter != null) { parameter.setParent(this); parameter.setPropertyInParent(FUNCTION_PARAMETER); - parameters = (IASTParameterDeclaration []) ArrayUtil.append( IASTParameterDeclaration.class, parameters, ++parametersPos, parameter ); + parameters = (IASTParameterDeclaration[]) ArrayUtil.append(IASTParameterDeclaration.class, parameters, ++parametersPos, parameter); } } @@ -66,12 +68,10 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS varArgs = value; } - public boolean isConst() { return isConst; } - public void setConst(boolean value) { this.isConst = value; } @@ -84,82 +84,73 @@ public class CPPASTFunctionDeclarator extends CPPASTDeclarator implements ICPPAS this.isVolatile = value; } - private IASTTypeId [] typeIds = null; - private int typeIdsPos=-1; - public IASTTypeId[] getExceptionSpecification() { - if( typeIds == null ) return IASTTypeId.EMPTY_TYPEID_ARRAY; - typeIds = (IASTTypeId[]) ArrayUtil.removeNullsAfter( IASTTypeId.class, typeIds, typeIdsPos ); + if (typeIds == null) return IASTTypeId.EMPTY_TYPEID_ARRAY; + typeIds = (IASTTypeId[]) ArrayUtil.removeNullsAfter(IASTTypeId.class, typeIds, typeIdsPos); return typeIds; } - public void addExceptionSpecificationTypeId(IASTTypeId typeId) { if (typeId != null) { - typeIds = (IASTTypeId[]) ArrayUtil.append( IASTTypeId.class, typeIds, ++typeIdsPos, typeId ); + typeIds = (IASTTypeId[]) ArrayUtil.append(IASTTypeId.class, typeIds, ++typeIdsPos, typeId); typeId.setParent(this); typeId.setPropertyInParent(EXCEPTION_TYPEID); } } - public boolean isPureVirtual() { return pureVirtual; } - public void setPureVirtual(boolean isPureVirtual) { this.pureVirtual = isPureVirtual; } - - private ICPPASTConstructorChainInitializer [] constructorChain = null; - private int constructorChainPos=-1; - - public ICPPASTConstructorChainInitializer[] getConstructorChain() { - if( constructorChain == null ) return ICPPASTConstructorChainInitializer.EMPTY_CONSTRUCTORCHAININITIALIZER_ARRAY; - constructorChain = (ICPPASTConstructorChainInitializer[]) ArrayUtil.removeNullsAfter( ICPPASTConstructorChainInitializer.class, constructorChain, constructorChainPos ); + if (constructorChain == null) return ICPPASTConstructorChainInitializer.EMPTY_CONSTRUCTORCHAININITIALIZER_ARRAY; + constructorChain = (ICPPASTConstructorChainInitializer[]) ArrayUtil.removeNullsAfter( + ICPPASTConstructorChainInitializer.class, constructorChain, constructorChainPos); return constructorChain; } - public void addConstructorToChain(ICPPASTConstructorChainInitializer initializer) { if (initializer != null) { - constructorChain = (ICPPASTConstructorChainInitializer[]) ArrayUtil.append(ICPPASTConstructorChainInitializer.class, constructorChain, ++constructorChainPos, initializer ); + constructorChain = (ICPPASTConstructorChainInitializer[]) ArrayUtil.append( + ICPPASTConstructorChainInitializer.class, constructorChain, ++constructorChainPos, initializer); initializer.setParent(this); initializer.setPropertyInParent(CONSTRUCTOR_CHAIN_MEMBER); } } - public ICPPFunctionScope getFunctionScope(){ - if( scope != null ) + public ICPPFunctionScope getFunctionScope() { + if (scope != null) return scope; ASTNodeProperty prop = getPropertyInParent(); - if( prop == IASTSimpleDeclaration.DECLARATOR || prop == IASTFunctionDefinition.DECLARATOR ) - scope = new CPPFunctionScope( this ); + if (prop == IASTSimpleDeclaration.DECLARATOR || prop == IASTFunctionDefinition.DECLARATOR) { + scope = new CPPFunctionScope(this); + } return scope; } @Override - protected boolean postAccept( ASTVisitor action ){ - IASTParameterDeclaration [] params = getParameters(); - for ( int i = 0; i < params.length; i++ ) { - if( !params[i].accept( action ) ) return false; + protected boolean postAccept(ASTVisitor action) { + IASTParameterDeclaration[] params = getParameters(); + for (int i = 0; i < params.length; i++) { + if (!params[i].accept(action)) return false; } - ICPPASTConstructorChainInitializer [] chain = getConstructorChain(); - for ( int i = 0; i < chain.length; i++ ) { - if( !chain[i].accept( action ) ) return false; + ICPPASTConstructorChainInitializer[] chain = getConstructorChain(); + for (int i = 0; i < chain.length; i++) { + if (!chain[i].accept(action)) return false; } IASTInitializer initializer = getInitializer(); - if( initializer != null ) if( !initializer.accept( action ) ) return false; + if (initializer != null && !initializer.accept(action)) return false; IASTTypeId[] ids = getExceptionSpecification(); - for ( int i = 0; i < ids.length; i++ ) { - if( !ids[i].accept( action ) ) return false; + for (int i = 0; i < ids.length; i++) { + if (!ids[i].accept(action)) return false; } return true; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java index 151cdd73cfb..2a4b9714ca7 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPTypedefSpecialization.java @@ -48,8 +48,11 @@ public class CPPTypedefSpecialization extends CPPSpecialization implements IType public IType getType() throws DOMException { if (type == null) { type = CPPTemplates.instantiateType(getTypedef().getType(), argumentMap, getScope()); - if (type == this) { - // A typedef pointing to itself is a sure recipe for an infinite loop. + // A typedef pointing to itself is a sure recipe for an infinite loop -- replace with + // a problem binding. + if (type instanceof CPPTypedefSpecialization && + ((CPPTypedefSpecialization) type).getSpecializedBinding().equals(getSpecializedBinding()) && + ((CPPTypedefSpecialization) type).getArgumentMap().isSame(argumentMap, IType.TYPE_COMPARATOR)) { type = new ProblemBinding(getDefinition(), IProblemBinding.SEMANTIC_INVALID_TYPE, getNameCharArray()); } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassTemplate.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassTemplate.java index 9fdcb720c7c..8a2a9a92fb6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassTemplate.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPClassTemplate.java @@ -67,6 +67,8 @@ class PDOMCPPClassTemplate extends PDOMCPPClassType @SuppressWarnings("hiding") protected static final int RECORD_SIZE = PDOMCPPClassType.RECORD_SIZE + 16; + private ICPPTemplateParameter[] params; // Cached template parameters. + public PDOMCPPClassTemplate(PDOM pdom, PDOMNode parent, ICPPClassTemplate template) throws CoreException { super(pdom, parent, template); } @@ -100,16 +102,21 @@ class PDOMCPPClassTemplate extends PDOMCPPClassType } public ICPPTemplateParameter[] getTemplateParameters() { - try { - PDOMNodeLinkedList list = new PDOMNodeLinkedList(pdom, record + PARAMETERS, getLinkageImpl()); - TemplateParameterCollector visitor = new TemplateParameterCollector(); - list.accept(visitor); - - return visitor.getTemplateParameters(); - } catch (CoreException e) { - CCorePlugin.log(e); - return new ICPPTemplateParameter[0]; + if (params == null) { + try { + PDOMNodeLinkedList list = new PDOMNodeLinkedList(pdom, record + PARAMETERS, getLinkageImpl()); + TemplateParameterCollector visitor = new TemplateParameterCollector(); + list.accept(visitor); + params = visitor.getTemplateParameters(); + } catch (CoreException e) { + CCorePlugin.log(e); + params = ICPPTemplateParameter.EMPTY_TEMPLATE_PARAMETER_ARRAY; + } } + // Copy to a new array for safety. + ICPPTemplateParameter[] result = new ICPPTemplateParameter[params.length]; + System.arraycopy(params, 0, result, 0, params.length); + return result; } private PDOMCPPClassTemplatePartialSpecialization getFirstPartial() throws CoreException { @@ -310,7 +317,7 @@ class PDOMCPPClassTemplate extends PDOMCPPClassType if (template instanceof IProblemBinding) return template; if (template != null && template instanceof ICPPClassTemplatePartialSpecialization) { - return ((PDOMCPPClassTemplate)template).instantiate(arguments); + return ((PDOMCPPClassTemplate) template).instantiate(arguments); } return CPPTemplates.instantiateTemplate(this, arguments, null);