mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-24 09:25:31 +02:00
Bug 491834 - Avoid certain kinds of infinte recursion in HeuristicResolver
This is done by tracking the set of lookups of names in primary template scopes performed during a heuristic resolution, and short-circuiting a resoluton if the same lookup is attempted twice. Change-Id: I512cdc9493d1ac91b1f77603d816a33312d4be00
This commit is contained in:
parent
2392400649
commit
50eca42cb1
2 changed files with 77 additions and 17 deletions
|
@ -10,6 +10,9 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||
|
@ -33,6 +36,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPEnumeration;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPDeferredClassInstance;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPEvaluation;
|
||||
|
@ -211,6 +215,36 @@ public class HeuristicResolver {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a lookup of a name in a primary template scope.
|
||||
* The set of such lookups during a heuristic resolution operation is
|
||||
* tracked, to avoid infinite recursion.
|
||||
*/
|
||||
private static class HeuristicLookup {
|
||||
public IScope scope;
|
||||
public char[] name;
|
||||
|
||||
public HeuristicLookup(IScope scope, char[] name) {
|
||||
this.scope = scope;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof HeuristicLookup)) {
|
||||
return false;
|
||||
}
|
||||
HeuristicLookup otherLookup = (HeuristicLookup) other;
|
||||
return scope == otherLookup.scope
|
||||
&& CharArrayUtils.equals(name, otherLookup.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return scope.hashCode() * (29 + name.hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for resolveUnknownType() and resolveUnknownBinding().
|
||||
* Heuristically resolves the given unknown type and performs name lookup inside it.
|
||||
|
@ -223,11 +257,12 @@ public class HeuristicResolver {
|
|||
* @param isPointerDeref true if 'ownerType' is a pointer type
|
||||
* @param name the name to be looked up
|
||||
* @param templateArgs template arguments following the name, if any
|
||||
* @param lookupSet the set of lookups performed so far; lookups during this call are added to this
|
||||
* @param point point of instantiation for name lookups
|
||||
* @return results of the name lookup
|
||||
*/
|
||||
private static IBinding[] lookInside(IType ownerType, boolean isPointerDeref, char[] name,
|
||||
ICPPTemplateArgument[] templateArgs, IASTNode point) {
|
||||
ICPPTemplateArgument[] templateArgs, Set<HeuristicLookup> lookupSet, IASTNode point) {
|
||||
// If this is a pointer dereference, the pointer type might be outside of the dependent type.
|
||||
ownerType = SemanticUtil.getSimplifiedType(ownerType);
|
||||
if (isPointerDeref && ownerType instanceof IPointerType) {
|
||||
|
@ -252,7 +287,8 @@ public class HeuristicResolver {
|
|||
lookupType = specializationContext.getSpecializedBinding();
|
||||
break;
|
||||
}
|
||||
IType resolvedType = resolveUnknownTypeOnce((ICPPUnknownType) lookupType, point);
|
||||
IType resolvedType = resolveUnknownTypeOnce((ICPPUnknownType) lookupType, lookupSet,
|
||||
point);
|
||||
resolvedType = SemanticUtil.getNestedType(resolvedType, SemanticUtil.TDEF | SemanticUtil.REF);
|
||||
if (resolvedType == lookupType || !(resolvedType instanceof ICPPUnknownType)) {
|
||||
lookupType = resolvedType;
|
||||
|
@ -281,18 +317,21 @@ public class HeuristicResolver {
|
|||
lookupScope = ((ICPPEnumeration) lookupType).asScope();
|
||||
}
|
||||
if (lookupScope != null) {
|
||||
LookupData lookup = new LookupData(name, templateArgs, point);
|
||||
lookup.fHeuristicBaseLookup = true;
|
||||
try {
|
||||
CPPSemantics.lookup(lookup, lookupScope);
|
||||
IBinding[] foundBindings = lookup.getFoundBindings();
|
||||
if (foundBindings.length > 0) {
|
||||
if (specializationContext != null) {
|
||||
foundBindings = specializeBindings(foundBindings, specializationContext, point);
|
||||
HeuristicLookup entry = new HeuristicLookup(lookupScope, name);
|
||||
if (lookupSet.add(entry)) {
|
||||
LookupData lookup = new LookupData(name, templateArgs, point);
|
||||
lookup.fHeuristicBaseLookup = true;
|
||||
try {
|
||||
CPPSemantics.lookup(lookup, lookupScope);
|
||||
IBinding[] foundBindings = lookup.getFoundBindings();
|
||||
if (foundBindings.length > 0) {
|
||||
if (specializationContext != null) {
|
||||
foundBindings = specializeBindings(foundBindings, specializationContext, point);
|
||||
}
|
||||
return foundBindings;
|
||||
}
|
||||
return foundBindings;
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
}
|
||||
return IBinding.EMPTY_BINDING_ARRAY;
|
||||
|
@ -340,7 +379,8 @@ public class HeuristicResolver {
|
|||
*/
|
||||
private static IType resolveUnknownType(ICPPUnknownType type, IASTNode point, int unwrapOptions) {
|
||||
while (true) {
|
||||
IType resolvedType = resolveUnknownTypeOnce(type, point);
|
||||
Set<HeuristicLookup> lookupSet = new HashSet<>();
|
||||
IType resolvedType = resolveUnknownTypeOnce(type, lookupSet, point);
|
||||
resolvedType = SemanticUtil.getNestedType(resolvedType, unwrapOptions);
|
||||
if (resolvedType != type && resolvedType instanceof ICPPUnknownType) {
|
||||
type = (ICPPUnknownType) resolvedType;
|
||||
|
@ -353,7 +393,8 @@ public class HeuristicResolver {
|
|||
/**
|
||||
* Helper function for {@link #resolveUnknownType} which does one round of resolution.
|
||||
*/
|
||||
private static IType resolveUnknownTypeOnce(ICPPUnknownType type, IASTNode point) {
|
||||
private static IType resolveUnknownTypeOnce(ICPPUnknownType type, Set<HeuristicLookup> lookupSet,
|
||||
IASTNode point) {
|
||||
// Guard against infinite recursion.
|
||||
int resolutionDepth = fResolutionDepth.get();
|
||||
if (resolutionDepth > RESOLUTION_DEPTH_LIMIT) {
|
||||
|
@ -387,7 +428,7 @@ public class HeuristicResolver {
|
|||
if (fieldOwner != null) {
|
||||
IType fieldOwnerType = fieldOwner.getType(point);
|
||||
IBinding[] candidates = lookInside(fieldOwnerType, id.isPointerDeref(), id.getName(),
|
||||
id.getTemplateArgs(), point);
|
||||
id.getTemplateArgs(), lookupSet, point);
|
||||
if (candidates.length == 1) {
|
||||
return typeForBinding(candidates[0]);
|
||||
}
|
||||
|
@ -410,7 +451,8 @@ public class HeuristicResolver {
|
|||
} else if (type instanceof ICPPUnknownMemberClass) {
|
||||
ICPPUnknownMemberClass member = (ICPPUnknownMemberClass) type;
|
||||
IType ownerType = member.getOwnerType();
|
||||
IBinding[] candidates = lookInside(ownerType, false, member.getNameCharArray(), null, point);
|
||||
IBinding[] candidates = lookInside(ownerType, false, member.getNameCharArray(), null,
|
||||
lookupSet, point);
|
||||
if (candidates.length == 1) {
|
||||
if (candidates[0] instanceof IType) {
|
||||
IType result = (IType) candidates[0];
|
||||
|
@ -452,8 +494,9 @@ public class HeuristicResolver {
|
|||
if (binding instanceof ICPPDeferredClassInstance) {
|
||||
return new IBinding[] { ((ICPPDeferredClassInstance) binding).getClassTemplate() };
|
||||
} else if (binding instanceof ICPPUnknownMember) {
|
||||
Set<HeuristicLookup> lookupSet = new HashSet<>();
|
||||
return lookInside(((ICPPUnknownMember) binding).getOwnerType(), false,
|
||||
binding.getNameCharArray(), null, point);
|
||||
binding.getNameCharArray(), null, lookupSet, point);
|
||||
}
|
||||
return IBinding.EMPTY_BINDING_ARRAY;
|
||||
}
|
||||
|
|
|
@ -546,4 +546,21 @@ public class SemanticHighlightingTest extends TestCase {
|
|||
public void testOverloadedOperatorInMacroExpansion_371839() throws Exception {
|
||||
makeAssertions();
|
||||
}
|
||||
|
||||
// template<unsigned... _Indexes> //$templateParameter
|
||||
// struct _Index_tuple { //$class
|
||||
// typedef _Index_tuple<_Indexes..., sizeof...(_Indexes)> __next; //$class,templateParameter,templateParameter,typedef
|
||||
// };
|
||||
// template<unsigned _Num> //$templateParameter
|
||||
// struct _Build_index_tuple { //$class
|
||||
// typedef typename _Build_index_tuple<_Num - 1>::__type::__next __type; //$class,templateParameter,class,class,typedef
|
||||
// };
|
||||
//
|
||||
// template<>
|
||||
// struct _Build_index_tuple<0> { //$class
|
||||
// typedef _Index_tuple<> __type; //$class,typedef
|
||||
// };
|
||||
public void testRecursion_491834() throws Exception {
|
||||
makeAssertions();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue