mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-04 14:55:41 +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();
|
final String code = getAboveComment();
|
||||||
parseAndCheckBindings(code, ParserLanguage.CPP);
|
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 char[] arg;
|
||||||
protected IASTNode node;
|
protected IASTNode node;
|
||||||
private final String message = null;
|
private final String message = null;
|
||||||
private final IBinding[] candidateBindings;
|
private IBinding[] candidateBindings;
|
||||||
|
|
||||||
public ProblemBinding(IASTName name, int id) {
|
public ProblemBinding(IASTName name, int id) {
|
||||||
this(name, id, null, null);
|
this(name, id, null, null);
|
||||||
|
@ -74,6 +74,10 @@ public class ProblemBinding extends PlatformObject implements IProblemBinding, I
|
||||||
return candidateBindings != null ? candidateBindings : IBinding.EMPTY_BINDING_ARRAY;
|
return candidateBindings != null ? candidateBindings : IBinding.EMPTY_BINDING_ARRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCandidateBindings(IBinding[] foundBindings) {
|
||||||
|
candidateBindings= foundBindings;
|
||||||
|
}
|
||||||
|
|
||||||
protected static final String[] errorMessages;
|
protected static final String[] errorMessages;
|
||||||
static {
|
static {
|
||||||
errorMessages = new String[IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS];
|
errorMessages = new String[IProblemBinding.SEMANTIC_INVALID_TEMPLATE_ARGUMENTS];
|
||||||
|
|
|
@ -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.ICPPClassSpecializationScope;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
|
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.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.ICPPUnknownBinding;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
|
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.
|
* 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 =
|
public static final ASTNodeProperty STRING_LOOKUP_PROPERTY =
|
||||||
new ASTNodeProperty("CPPSemantics.STRING_LOOKUP_PROPERTY - STRING_LOOKUP"); //$NON-NLS-1$
|
new ASTNodeProperty("CPPSemantics.STRING_LOOKUP_PROPERTY - STRING_LOOKUP"); //$NON-NLS-1$
|
||||||
|
@ -207,8 +206,6 @@ public class CPPSemantics {
|
||||||
|
|
||||||
// special return value for costForFunctionCall
|
// special return value for costForFunctionCall
|
||||||
private static final FunctionCost CONTAINS_DEPENDENT_TYPES = new FunctionCost(null, 0);
|
private static final FunctionCost CONTAINS_DEPENDENT_TYPES = new FunctionCost(null, 0);
|
||||||
|
|
||||||
|
|
||||||
static protected IBinding resolveBinding(IASTName name) {
|
static protected IBinding resolveBinding(IASTName name) {
|
||||||
if (traceBindingResolution) {
|
if (traceBindingResolution) {
|
||||||
for (int i = 0; i < traceIndent; i++)
|
for (int i = 0; i < traceIndent; i++)
|
||||||
|
@ -681,7 +678,7 @@ public class CPPSemantics {
|
||||||
* @param scoped
|
* @param scoped
|
||||||
* @return
|
* @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;
|
if (source == null) return dest;
|
||||||
CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2);
|
CharArrayObjectMap resultMap = (dest != null) ? dest : new CharArrayObjectMap(2);
|
||||||
|
|
||||||
|
@ -848,7 +845,7 @@ public class CPPSemantics {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.usingDirectivesOnly && scope instanceof ICPPClassScope) {
|
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()))
|
if (!data.contentAssist && (data.problem != null || data.hasResults()))
|
||||||
|
@ -968,7 +965,7 @@ public class CPPSemantics {
|
||||||
return result[0];
|
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;
|
IBinding[] bindings;
|
||||||
if (scope instanceof ICPPASTInternalScope) {
|
if (scope instanceof ICPPASTInternalScope) {
|
||||||
bindings= ((ICPPASTInternalScope) scope).getBindings(data.astName, true, data.prefixLookup, fileSet, data.checkPointOfDecl);
|
bindings= ((ICPPASTInternalScope) scope).getBindings(data.astName, true, data.prefixLookup, fileSet, data.checkPointOfDecl);
|
||||||
|
@ -978,7 +975,7 @@ public class CPPSemantics {
|
||||||
return bindings;
|
return bindings;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void removeObjects(final IBinding[] bindings) {
|
static void removeObjects(final IBinding[] bindings) {
|
||||||
final int length = bindings.length;
|
final int length = bindings.length;
|
||||||
int pos= 0;
|
int pos= 0;
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
|
@ -1033,230 +1030,6 @@ public class CPPSemantics {
|
||||||
return (ICPPScope) parentScope;
|
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.
|
* 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.List;
|
||||||
import java.util.Map;
|
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.c.ICASTFieldDesignator;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer;
|
||||||
|
@ -64,10 +88,6 @@ public class LookupData {
|
||||||
*/
|
*/
|
||||||
public ObjectSet<IScope> visited= new ObjectSet<IScope>(1);
|
public ObjectSet<IScope> visited= new ObjectSet<IScope>(1);
|
||||||
|
|
||||||
/*
|
|
||||||
* Used to detect circular inheritance
|
|
||||||
*/
|
|
||||||
public ObjectSet<IScope> inheritanceChain;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public ObjectSet<IScope> associated = ObjectSet.EMPTY_SET;
|
public ObjectSet<IScope> associated = ObjectSet.EMPTY_SET;
|
||||||
|
@ -560,8 +580,8 @@ public class LookupData {
|
||||||
}
|
}
|
||||||
if (checkForDependentName) {
|
if (checkForDependentName) {
|
||||||
IType[] types= getFunctionArgumentTypes();
|
IType[] types= getFunctionArgumentTypes();
|
||||||
for (int i = 0; i < types.length; i++) {
|
for (IType type : types) {
|
||||||
if (CPPTemplates.isDependentType(types[i])) {
|
if (CPPTemplates.isDependentType(type)) {
|
||||||
checkPointOfDecl= false;
|
checkPointOfDecl= false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue