mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-23 17:05:26 +02:00
Hidden virtual bases, bug 282993.
This commit is contained in:
parent
818d85f171
commit
6b57ac7cf2
5 changed files with 432 additions and 240 deletions
|
@ -7237,4 +7237,34 @@ public class AST2CPPTests extends AST2BaseTest {
|
|||
final String code = getAboveComment();
|
||||
parseAndCheckBindings(code, ParserLanguage.CPP);
|
||||
}
|
||||
|
||||
// class IBase {
|
||||
// public:
|
||||
// virtual void base() = 0;
|
||||
// };
|
||||
//
|
||||
// class IDerived : virtual public IBase {
|
||||
// public:
|
||||
// virtual void derived() = 0;
|
||||
// };
|
||||
//
|
||||
// class BaseImplHelper : virtual public IBase {
|
||||
// public:
|
||||
// virtual void base() {}
|
||||
// };
|
||||
//
|
||||
// class Derived : virtual public IDerived, public BaseImplHelper {
|
||||
// public:
|
||||
// virtual void derived() {}
|
||||
// };
|
||||
//
|
||||
// int main() {
|
||||
// Derived d;
|
||||
// d.base(); // Parser log reports ambiguity on 'base'
|
||||
// return 0;
|
||||
// }
|
||||
public void testHiddenVirtualBase_Bug282993() throws Exception {
|
||||
final String code = getAboveComment();
|
||||
parseAndCheckBindings(code, ParserLanguage.CPP);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public class ProblemBinding extends PlatformObject implements IProblemBinding, I
|
|||
protected char[] arg;
|
||||
protected IASTNode node;
|
||||
private final String message = null;
|
||||
private final IBinding[] candidateBindings;
|
||||
private IBinding[] candidateBindings;
|
||||
|
||||
public ProblemBinding(IASTName name, int id) {
|
||||
this(name, id, null, null);
|
||||
|
@ -73,6 +73,10 @@ public class ProblemBinding extends PlatformObject implements IProblemBinding, I
|
|||
public IBinding[] getCandidateBindings() {
|
||||
return candidateBindings != null ? candidateBindings : IBinding.EMPTY_BINDING_ARRAY;
|
||||
}
|
||||
|
||||
public void setCandidateBindings(IBinding[] foundBindings) {
|
||||
candidateBindings= foundBindings;
|
||||
}
|
||||
|
||||
protected static final String[] errorMessages;
|
||||
static {
|
||||
|
|
|
@ -0,0 +1,365 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2009 Wind River Systems, 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:
|
||||
* Markus Schorn - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember;
|
||||
import org.eclipse.cdt.core.index.IIndexFileSet;
|
||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalUnknownScope;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
|
||||
|
||||
/**
|
||||
* Helper class for performing the base class lookup. First a directed graph without loops is computed to represent the base
|
||||
* class hierarchy up to those bases for which the lookup finds matches. Next, from these leaves we search for virtual bases
|
||||
* that are hidden. With this information the matches are extracted from the graph.
|
||||
*/
|
||||
class BaseClassLookup {
|
||||
public static void lookupInBaseClasses(LookupData data, ICPPClassScope classScope, IIndexFileSet fileSet) {
|
||||
if (classScope == null)
|
||||
return;
|
||||
|
||||
final ICPPClassType classType= classScope.getClassType();
|
||||
if (classType == null)
|
||||
return;
|
||||
|
||||
final HashMap<IScope, BaseClassLookup> infoMap = new HashMap<IScope, BaseClassLookup>();
|
||||
BaseClassLookup rootInfo= lookupInBaseClass(data, null, false, classType, fileSet, infoMap, 0);
|
||||
if (data.contentAssist) {
|
||||
rootInfo.collectResultForContentAssist(data);
|
||||
} else {
|
||||
hideVirtualBases(rootInfo, infoMap);
|
||||
IBinding[] result= rootInfo.collectResult(data, true, null);
|
||||
verifyResult(data, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final ICPPClassType fClassType;
|
||||
private IBinding[] fBindings;
|
||||
private List<BaseClassLookup> fChildren= Collections.emptyList();
|
||||
private BitSet fVirtual;
|
||||
private boolean fHiddenAsVirtualBase= false;
|
||||
private boolean fPropagationDone= false;
|
||||
private boolean fCollected;
|
||||
private boolean fCollectedAsRegularBase;
|
||||
|
||||
private BaseClassLookup(ICPPClassType type) {
|
||||
fClassType= type;
|
||||
}
|
||||
ICPPClassType getClassType() {
|
||||
return fClassType;
|
||||
}
|
||||
|
||||
IBinding[] getResult() {
|
||||
return fBindings;
|
||||
}
|
||||
boolean containsVirtualBase() {
|
||||
return (fVirtual != null && fVirtual.nextSetBit(0) >= 0);
|
||||
}
|
||||
boolean hasMatches() {
|
||||
return fBindings != null && fBindings.length > 0 && fBindings[0] != null;
|
||||
}
|
||||
|
||||
public void addBase(boolean virtual, BaseClassLookup baseInfo) {
|
||||
if (virtual && fHiddenAsVirtualBase)
|
||||
return;
|
||||
|
||||
if (fChildren.isEmpty()) {
|
||||
fChildren= new ArrayList<BaseClassLookup>();
|
||||
fVirtual= new BitSet();
|
||||
}
|
||||
fVirtual.set(fChildren.size(), virtual);
|
||||
fChildren.add(baseInfo);
|
||||
}
|
||||
|
||||
public void setResult(IBinding[] bindings) {
|
||||
fBindings= bindings;
|
||||
}
|
||||
|
||||
public void setHiddenAsVirtualBase() {
|
||||
fHiddenAsVirtualBase= true;
|
||||
}
|
||||
public void propagateHiddenAsVirtual() {
|
||||
if (fPropagationDone)
|
||||
return;
|
||||
fPropagationDone= true;
|
||||
for (int i=0; i<fChildren.size(); i++) {
|
||||
BaseClassLookup child = fChildren.get(i);
|
||||
if (fVirtual.get(i)) {
|
||||
child.setHiddenAsVirtualBase();
|
||||
}
|
||||
child.propagateHiddenAsVirtual();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean containsNonStaticMember() {
|
||||
for (IBinding binding : fBindings) {
|
||||
if (binding == null)
|
||||
return false;
|
||||
if (binding instanceof ICPPMember) {
|
||||
try {
|
||||
if (!((ICPPMember) binding).isStatic())
|
||||
return true;
|
||||
} catch (DOMException e) {
|
||||
// treat as non-static
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static BaseClassLookup lookupInBaseClass(LookupData data, ICPPClassScope baseClassScope, boolean isVirtual, ICPPClassType root, IIndexFileSet fileSet, HashMap<IScope, BaseClassLookup> infoMap, int depth) {
|
||||
if (depth++ > CPPSemantics.MAX_INHERITANCE_DEPTH)
|
||||
return null;
|
||||
|
||||
if (baseClassScope != null) {
|
||||
BaseClassLookup info= infoMap.get(baseClassScope);
|
||||
if (info != null) {
|
||||
// avoid loops
|
||||
if (info.getResult() == null) {
|
||||
data.problem = new ProblemBinding(null, IProblemBinding.SEMANTIC_CIRCULAR_INHERITANCE, root.getNameCharArray());
|
||||
return null;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
// this is the first time to handle the class
|
||||
BaseClassLookup result;
|
||||
IBinding[] matches= IBinding.EMPTY_BINDING_ARRAY;
|
||||
if (baseClassScope == null) {
|
||||
result= new BaseClassLookup(root);
|
||||
try {
|
||||
infoMap.put(root.getCompositeScope(), result);
|
||||
} catch (DOMException e) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
result= new BaseClassLookup(baseClassScope.getClassType());
|
||||
infoMap.put(baseClassScope, result);
|
||||
try {
|
||||
IBinding[] members= CPPSemantics.getBindingsFromScope(baseClassScope, fileSet, data);
|
||||
if (data.typesOnly) {
|
||||
CPPSemantics.removeObjects(members);
|
||||
}
|
||||
if (members != null && members.length > 0 && members[0] != null) {
|
||||
if (data.prefixLookup) {
|
||||
matches= members;
|
||||
} else {
|
||||
result.setResult(members);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
// continue the lookup
|
||||
}
|
||||
}
|
||||
|
||||
// there is no result in the baseClass itself or we do content assist, we have to examine its base-classes
|
||||
ICPPClassType baseClass= result.getClassType();
|
||||
if (baseClass != null) {
|
||||
ICPPBase[] grandBases= null;
|
||||
try {
|
||||
grandBases= baseClass.getBases();
|
||||
} catch (DOMException e) {
|
||||
// assume that there are no bases
|
||||
}
|
||||
if (grandBases != null && grandBases.length > 0) {
|
||||
HashSet<IBinding> grandBaseBindings= grandBases.length > 1 ? new HashSet<IBinding>() : null;
|
||||
for (ICPPBase grandBase : grandBases) {
|
||||
if (grandBase instanceof IProblemBinding)
|
||||
continue;
|
||||
|
||||
try {
|
||||
IBinding grandBaseBinding = grandBase.getBaseClass();
|
||||
if (!(grandBaseBinding instanceof ICPPClassType)) {
|
||||
// 14.6.2.3 scope is not examined
|
||||
if (grandBaseBinding instanceof ICPPUnknownBinding) {
|
||||
if (data.skippedScope == null)
|
||||
data.skippedScope= root;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final ICPPClassType grandBaseClass = (ICPPClassType) grandBaseBinding;
|
||||
if (grandBaseBindings != null && !grandBaseBindings.add(grandBaseClass))
|
||||
continue;
|
||||
|
||||
final IScope grandBaseScope= grandBaseClass.getCompositeScope();
|
||||
if (grandBaseScope == null || grandBaseScope instanceof ICPPInternalUnknownScope) {
|
||||
// 14.6.2.3 scope is not examined
|
||||
if (data.skippedScope == null)
|
||||
data.skippedScope= root;
|
||||
continue;
|
||||
}
|
||||
if (!(grandBaseScope instanceof ICPPClassScope))
|
||||
continue;
|
||||
|
||||
BaseClassLookup baseInfo= lookupInBaseClass(data, (ICPPClassScope) grandBaseScope, grandBase.isVirtual(), root, fileSet, infoMap, depth);
|
||||
if (baseInfo != null)
|
||||
result.addBase(grandBase.isVirtual(), baseInfo);
|
||||
} catch (DOMException e) {
|
||||
// move on to next base
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.setResult(matches);
|
||||
return result;
|
||||
}
|
||||
static void hideVirtualBases(BaseClassLookup rootInfo, HashMap<IScope, BaseClassLookup> infoMap) {
|
||||
boolean containsVirtualBase= false;
|
||||
final BaseClassLookup[] allInfos = infoMap.values().toArray(new BaseClassLookup[infoMap.size()]);
|
||||
for (BaseClassLookup info : allInfos) {
|
||||
if (info.containsVirtualBase()) {
|
||||
containsVirtualBase= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (containsVirtualBase) {
|
||||
for (BaseClassLookup info : allInfos) {
|
||||
if (info.hasMatches()) {
|
||||
info.hideVirtualBases(infoMap, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hideVirtualBases(HashMap<IScope, BaseClassLookup> infoMap, int depth) {
|
||||
if (depth++ > CPPSemantics.MAX_INHERITANCE_DEPTH)
|
||||
return;
|
||||
|
||||
if (fClassType != null) {
|
||||
ICPPBase[] bases= null;
|
||||
try {
|
||||
bases= fClassType.getBases();
|
||||
} catch (DOMException e) {
|
||||
// assume that there are no bases
|
||||
}
|
||||
if (bases != null && bases.length > 0) {
|
||||
for (ICPPBase base : bases) {
|
||||
if (base instanceof IProblemBinding)
|
||||
continue;
|
||||
|
||||
try {
|
||||
IBinding baseBinding = base.getBaseClass();
|
||||
if (!(baseBinding instanceof ICPPClassType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final ICPPClassType baseClass = (ICPPClassType) baseBinding;
|
||||
final IScope baseScope= baseClass.getCompositeScope();
|
||||
if (!(baseScope instanceof ICPPClassScope))
|
||||
continue;
|
||||
|
||||
BaseClassLookup baseInfo= infoMap.get(baseScope);
|
||||
if (baseInfo != null) {
|
||||
if (base.isVirtual()) {
|
||||
baseInfo.setHiddenAsVirtualBase();
|
||||
}
|
||||
baseInfo.propagateHiddenAsVirtual();
|
||||
} else {
|
||||
// mark to catch recursions
|
||||
baseInfo= new BaseClassLookup(baseClass);
|
||||
infoMap.put(baseScope, baseInfo);
|
||||
baseInfo.hideVirtualBases(infoMap, depth);
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
// move on to next base
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void collectResultForContentAssist(LookupData data) {
|
||||
if (fCollected)
|
||||
return;
|
||||
fCollected= true;
|
||||
|
||||
data.foundItems = CPPSemantics.mergePrefixResults((CharArrayObjectMap) data.foundItems, fBindings, true);
|
||||
for (int i=0; i<fChildren.size(); i++) {
|
||||
BaseClassLookup child = fChildren.get(i);
|
||||
child.collectResultForContentAssist(data);
|
||||
}
|
||||
}
|
||||
|
||||
public IBinding[] collectResult(LookupData data, boolean asVirtualBase, IBinding[] result) {
|
||||
if (asVirtualBase) {
|
||||
if (fHiddenAsVirtualBase)
|
||||
return result;
|
||||
} else {
|
||||
if (fCollectedAsRegularBase && data.problem == null && containsNonStaticMember()) {
|
||||
data.problem= new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP);
|
||||
}
|
||||
fCollectedAsRegularBase= true;
|
||||
}
|
||||
|
||||
if (fCollected)
|
||||
return result;
|
||||
fCollected= true;
|
||||
|
||||
result= (IBinding[]) ArrayUtil.addAll(IBinding.class, result, fBindings);
|
||||
for (int i=0; i<fChildren.size(); i++) {
|
||||
BaseClassLookup child = fChildren.get(i);
|
||||
result= child.collectResult(data, fVirtual.get(i), result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void verifyResult(LookupData data, IBinding[] bindings) {
|
||||
bindings= (IBinding[]) ArrayUtil.trim(IBinding.class, bindings);
|
||||
if (bindings.length == 0)
|
||||
return;
|
||||
|
||||
if (data.problem != null) {
|
||||
data.problem.setCandidateBindings(bindings);
|
||||
} else {
|
||||
ICPPClassType uniqueOwner= null;
|
||||
for (IBinding b : bindings) {
|
||||
if (!(b instanceof IType)) {
|
||||
try {
|
||||
IBinding owner= b.getOwner();
|
||||
if (owner instanceof ICPPClassType) {
|
||||
final ICPPClassType classOwner = (ICPPClassType) owner;
|
||||
if (uniqueOwner == null) {
|
||||
uniqueOwner= classOwner;
|
||||
} else if (!uniqueOwner.isSameType(classOwner)) {
|
||||
data.problem= new ProblemBinding(data.astName, IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, bindings);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.foundItems = ArrayUtil.addAll(Object.class, (Object[]) data.foundItems, bindings);
|
||||
}
|
||||
}
|
|
@ -176,7 +176,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPASTInternalScope;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPClassSpecializationScope;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPInternalUnknownScope;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
|
||||
|
@ -192,7 +191,7 @@ public class CPPSemantics {
|
|||
/**
|
||||
* The maximum depth to search ancestors before assuming infinite looping.
|
||||
*/
|
||||
public static final int MAX_INHERITANCE_DEPTH= 10;
|
||||
public static final int MAX_INHERITANCE_DEPTH= 16;
|
||||
|
||||
public static final ASTNodeProperty STRING_LOOKUP_PROPERTY =
|
||||
new ASTNodeProperty("CPPSemantics.STRING_LOOKUP_PROPERTY - STRING_LOOKUP"); //$NON-NLS-1$
|
||||
|
@ -207,8 +206,6 @@ public class CPPSemantics {
|
|||
|
||||
// special return value for costForFunctionCall
|
||||
private static final FunctionCost CONTAINS_DEPENDENT_TYPES = new FunctionCost(null, 0);
|
||||
|
||||
|
||||
static protected IBinding resolveBinding(IASTName name) {
|
||||
if (traceBindingResolution) {
|
||||
for (int i = 0; i < traceIndent; i++)
|
||||
|
@ -681,7 +678,7 @@ public class CPPSemantics {
|
|||
* @param scoped
|
||||
* @return
|
||||
*/
|
||||
private static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) {
|
||||
static CharArrayObjectMap mergePrefixResults(CharArrayObjectMap dest, Object source, boolean scoped) {
|
||||
if (source == null) return dest;
|
||||
CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2);
|
||||
|
||||
|
@ -848,7 +845,7 @@ public class CPPSemantics {
|
|||
}
|
||||
|
||||
if (!data.usingDirectivesOnly && scope instanceof ICPPClassScope) {
|
||||
mergeResults(data, lookupInParents(data, scope, ((ICPPClassScope) scope).getClassType(), fileSet), true);
|
||||
BaseClassLookup.lookupInBaseClasses(data, (ICPPClassScope) scope, fileSet);
|
||||
}
|
||||
|
||||
if (!data.contentAssist && (data.problem != null || data.hasResults()))
|
||||
|
@ -968,7 +965,7 @@ public class CPPSemantics {
|
|||
return result[0];
|
||||
}
|
||||
|
||||
private static IBinding[] getBindingsFromScope(ICPPScope scope, final IIndexFileSet fileSet, LookupData data) throws DOMException {
|
||||
static IBinding[] getBindingsFromScope(ICPPScope scope, final IIndexFileSet fileSet, LookupData data) throws DOMException {
|
||||
IBinding[] bindings;
|
||||
if (scope instanceof ICPPASTInternalScope) {
|
||||
bindings= ((ICPPASTInternalScope) scope).getBindings(data.astName, true, data.prefixLookup, fileSet, data.checkPointOfDecl);
|
||||
|
@ -978,7 +975,7 @@ public class CPPSemantics {
|
|||
return bindings;
|
||||
}
|
||||
|
||||
private static void removeObjects(final IBinding[] bindings) {
|
||||
static void removeObjects(final IBinding[] bindings) {
|
||||
final int length = bindings.length;
|
||||
int pos= 0;
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
@ -1033,230 +1030,6 @@ public class CPPSemantics {
|
|||
return (ICPPScope) parentScope;
|
||||
}
|
||||
|
||||
private static Object lookupInParents(LookupData data, ICPPScope lookIn, ICPPClassType overallScope, IIndexFileSet fileSet) {
|
||||
if (lookIn instanceof ICPPClassScope == false)
|
||||
return null;
|
||||
|
||||
final ICPPClassType classType= ((ICPPClassScope)lookIn).getClassType();
|
||||
if (classType == null)
|
||||
return null;
|
||||
|
||||
ICPPBase[] bases= null;
|
||||
try {
|
||||
bases= classType.getBases();
|
||||
} catch (DOMException e) {
|
||||
// assume that there are no bases
|
||||
return null;
|
||||
}
|
||||
if (bases == null || bases.length == 0)
|
||||
return null;
|
||||
|
||||
Object inherited = null;
|
||||
Object result = null;
|
||||
|
||||
//use data to detect circular inheritance
|
||||
if (data.inheritanceChain == null)
|
||||
data.inheritanceChain = new ObjectSet<IScope>(2);
|
||||
|
||||
data.inheritanceChain.put(lookIn);
|
||||
|
||||
// workaround to fix 185828
|
||||
if (data.inheritanceChain.size() > CPPSemantics.MAX_INHERITANCE_DEPTH) {
|
||||
return null;
|
||||
}
|
||||
|
||||
HashSet<IBinding> baseBindings= bases.length > 1 ? new HashSet<IBinding>() : null;
|
||||
for (ICPPBase base : bases) {
|
||||
if (base instanceof IProblemBinding)
|
||||
continue;
|
||||
|
||||
try {
|
||||
IBinding b = base.getBaseClass();
|
||||
if (!(b instanceof ICPPClassType)) {
|
||||
// 14.6.2.3 scope is not examined
|
||||
if (b instanceof ICPPUnknownBinding) {
|
||||
if (data.skippedScope == null)
|
||||
data.skippedScope= overallScope;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
final ICPPClassType cls = (ICPPClassType) b;
|
||||
if (baseBindings != null && !baseBindings.add(cls))
|
||||
continue;
|
||||
|
||||
inherited = null;
|
||||
final ICPPScope classScope = (ICPPScope) cls.getCompositeScope();
|
||||
if (classScope == null || classScope instanceof ICPPInternalUnknownScope) {
|
||||
// 14.6.2.3 scope is not examined
|
||||
if (data.skippedScope == null)
|
||||
data.skippedScope= overallScope;
|
||||
continue;
|
||||
}
|
||||
if (!base.isVirtual() || !data.visited.containsKey(classScope)) {
|
||||
if (base.isVirtual()) {
|
||||
data.visited.put(classScope);
|
||||
}
|
||||
|
||||
// if the inheritanceChain already contains the parent, then that
|
||||
// is circular inheritance
|
||||
if (!data.inheritanceChain.containsKey(classScope)) {
|
||||
//is this name define in this scope?
|
||||
IBinding[] inCurrentScope= getBindingsFromScope(classScope, fileSet, data);
|
||||
if (data.typesOnly) {
|
||||
removeObjects(inCurrentScope);
|
||||
}
|
||||
final boolean isEmpty= inCurrentScope.length == 0 || inCurrentScope[0] == null;
|
||||
if (data.contentAssist) {
|
||||
Object temp = lookupInParents(data, classScope, overallScope, fileSet);
|
||||
if (!isEmpty) {
|
||||
inherited = mergePrefixResults(null, inCurrentScope, true);
|
||||
inherited = mergePrefixResults((CharArrayObjectMap) inherited,
|
||||
(CharArrayObjectMap) temp, true);
|
||||
} else {
|
||||
inherited= temp;
|
||||
}
|
||||
} else if (isEmpty) {
|
||||
inherited= lookupInParents(data, classScope, overallScope, fileSet);
|
||||
} else {
|
||||
inherited= inCurrentScope;
|
||||
visitVirtualBaseClasses(data, cls);
|
||||
}
|
||||
} else {
|
||||
data.problem = new ProblemBinding(null, IProblemBinding.SEMANTIC_CIRCULAR_INHERITANCE,
|
||||
cls.getNameCharArray(), data.getFoundBindings());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (inherited != null) {
|
||||
if (result == null) {
|
||||
result = inherited;
|
||||
} else if (!data.contentAssist) {
|
||||
if (result instanceof Object[]) {
|
||||
Object[] r = (Object[]) result;
|
||||
for (int j = 0; j < r.length && r[j] != null; j++) {
|
||||
if (checkForAmbiguity(data, r[j], inherited)) {
|
||||
data.problem = new ProblemBinding(data.astName,
|
||||
IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (checkForAmbiguity(data, result, inherited)) {
|
||||
data.problem = new ProblemBinding(data.astName,
|
||||
IProblemBinding.SEMANTIC_AMBIGUOUS_LOOKUP, data.getFoundBindings());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
CharArrayObjectMap temp = (CharArrayObjectMap) inherited;
|
||||
CharArrayObjectMap r = (CharArrayObjectMap) result;
|
||||
char[] key = null;
|
||||
int tempSize = temp.size();
|
||||
for (int ii = 0; ii < tempSize; ii++) {
|
||||
key = temp.keyAt(ii);
|
||||
if (!r.containsKey(key)) {
|
||||
r.put(key, temp.get(key));
|
||||
} else {
|
||||
//TODO: prefixLookup ambiguity checking
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (DOMException e) {
|
||||
// assume that the base has not been specified
|
||||
}
|
||||
}
|
||||
|
||||
data.inheritanceChain.remove(lookIn);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void visitVirtualBaseClasses(LookupData data, ICPPClassType cls) throws DOMException {
|
||||
if (data.inheritanceChain == null)
|
||||
data.inheritanceChain = new ObjectSet<IScope>(2);
|
||||
|
||||
IScope scope = cls.getCompositeScope();
|
||||
if (scope != null)
|
||||
data.inheritanceChain.put(scope);
|
||||
|
||||
ICPPBase[] bases = cls.getBases();
|
||||
|
||||
for (ICPPBase base : bases) {
|
||||
IBinding b = base.getBaseClass();
|
||||
if (b instanceof ICPPClassType) {
|
||||
IScope bScope = ((ICPPClassType)b).getCompositeScope();
|
||||
if (base.isVirtual()) {
|
||||
if (bScope != null)
|
||||
data.visited.put(bScope);
|
||||
} else if (bScope != null) {
|
||||
if (!data.inheritanceChain.containsKey(bScope))
|
||||
visitVirtualBaseClasses(data, (ICPPClassType) b);
|
||||
else
|
||||
data.problem = new ProblemBinding(null, IProblemBinding.SEMANTIC_CIRCULAR_INHERITANCE, cls.getNameCharArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (scope != null)
|
||||
data.inheritanceChain.remove(scope);
|
||||
}
|
||||
|
||||
private static boolean checkForAmbiguity(LookupData data, Object n, Object names) throws DOMException {
|
||||
if (names instanceof Object[]) {
|
||||
names = ArrayUtil.trim(Object.class, (Object[]) names);
|
||||
if (((Object[])names).length == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
IBinding binding= (n instanceof IBinding) ? (IBinding) n : ((IASTName) n).resolveBinding();
|
||||
|
||||
int idx= 0;
|
||||
Object[] objs= null;
|
||||
Object o= names;
|
||||
if (names instanceof Object[]) {
|
||||
objs= (Object[]) names;
|
||||
o= objs[0];
|
||||
idx= 1;
|
||||
}
|
||||
|
||||
while (o != null) {
|
||||
IBinding b = (o instanceof IBinding) ? (IBinding) o : ((IASTName)o).resolveBinding();
|
||||
|
||||
if (b instanceof ICPPUsingDeclaration) {
|
||||
objs = ArrayUtil.append(Object.class, objs, ((ICPPUsingDeclaration)b).getDelegates());
|
||||
} else {
|
||||
if (binding != b)
|
||||
return true;
|
||||
|
||||
boolean ok = false;
|
||||
// 3.4.5-4 if the id-expression in a class member access is a qualified id... the result
|
||||
// is not required to be a unique base class...
|
||||
if (binding instanceof ICPPClassType) {
|
||||
IASTNode parent = data.astName.getParent();
|
||||
if (parent instanceof ICPPASTQualifiedName &&
|
||||
parent.getPropertyInParent() == IASTFieldReference.FIELD_NAME) {
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
// it is not ambiguous if they are the same thing and it is static or an enumerator
|
||||
if (binding instanceof IEnumerator ||
|
||||
(binding instanceof IFunction && ASTInternal.isStatic((IFunction) binding, false)) ||
|
||||
(binding instanceof IVariable && ((IVariable)binding).isStatic())) {
|
||||
ok = true;
|
||||
}
|
||||
if (!ok)
|
||||
return true;
|
||||
}
|
||||
if (objs != null && idx < objs.length)
|
||||
o = objs[idx++];
|
||||
else
|
||||
o = null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the using directive with the scope where the members of the nominated namespace will appear.
|
||||
|
|
|
@ -18,7 +18,31 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.*;
|
||||
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
|
||||
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier;
|
||||
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.IASTExpressionList;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionCallExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTInitializer;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IPointerType;
|
||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.c.ICASTFieldDesignator;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
|
||||
|
@ -64,10 +88,6 @@ public class LookupData {
|
|||
*/
|
||||
public ObjectSet<IScope> visited= new ObjectSet<IScope>(1);
|
||||
|
||||
/*
|
||||
* Used to detect circular inheritance
|
||||
*/
|
||||
public ObjectSet<IScope> inheritanceChain;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public ObjectSet<IScope> associated = ObjectSet.EMPTY_SET;
|
||||
|
@ -560,8 +580,8 @@ public class LookupData {
|
|||
}
|
||||
if (checkForDependentName) {
|
||||
IType[] types= getFunctionArgumentTypes();
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (CPPTemplates.isDependentType(types[i])) {
|
||||
for (IType type : types) {
|
||||
if (CPPTemplates.isDependentType(type)) {
|
||||
checkPointOfDecl= false;
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue