1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-23 17:05:26 +02:00

Mapping types of variables back to ast-types, if possible; bug 292749.

This commit is contained in:
Markus Schorn 2009-10-20 16:38:05 +00:00
parent 24ce8e3659
commit 353d1d0875
10 changed files with 256 additions and 14 deletions

View file

@ -233,6 +233,72 @@ public abstract class IndexBindingResolutionTestBase extends BaseTestCase {
assertQNEquals(expContainedTypeQN, (IBinding) containedType);
}
}
class SinglePDOMTestFirstASTStrategy implements ITestStrategy {
private IIndex index;
private ICProject cproject;
private StringBuffer[] testData;
private IASTTranslationUnit ast;
private boolean cpp;
public SinglePDOMTestFirstASTStrategy(boolean cpp) {
this.cpp = cpp;
}
public ICProject getCProject() {
return cproject;
}
public StringBuffer[] getTestData() {
return testData;
}
public IASTTranslationUnit getAst() {
return ast;
}
public void setUp() throws Exception {
cproject = cpp ? CProjectHelper.createCCProject(getName()+System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER)
: CProjectHelper.createCProject(getName()+System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER);
Bundle b = CTestPlugin.getDefault().getBundle();
testData = TestSourceReader.getContentsForTest(b, "parser", IndexBindingResolutionTestBase.this.getClass(), getName(), 2);
if (testData.length < 2)
return;
IFile file = TestSourceReader.createFile(cproject.getProject(), new Path("header.h"), testData[0].toString());
CCorePlugin.getIndexManager().setIndexerId(cproject, IPDOMManager.ID_FAST_INDEXER);
assertTrue(CCorePlugin.getIndexManager().joinIndexer(360000, new NullProgressMonitor()));
if (DEBUG) {
System.out.println("Project PDOM: "+getName());
((PDOM)CCoreInternals.getPDOMManager().getPDOM(cproject)).accept(new PDOMPrettyPrinter());
}
index= CCorePlugin.getIndexManager().getIndex(cproject);
index.acquireReadLock();
IFile cppfile= TestSourceReader.createFile(cproject.getProject(), new Path("references.c" + (cpp ? "pp" : "")), testData[1].toString());
ast = TestSourceReader.createIndexBasedAST(index, cproject, cppfile);
}
public void tearDown() throws Exception {
if (index != null) {
index.releaseReadLock();
}
if (cproject != null) {
cproject.getProject().delete(IResource.FORCE | IResource.ALWAYS_DELETE_PROJECT_CONTENT, new NullProgressMonitor());
}
}
public IIndex getIndex() {
return index;
}
public boolean isCompositeIndex() {
return false;
}
}
class SinglePDOMTestStrategy implements ITestStrategy {
private IIndex index;

View file

@ -64,13 +64,14 @@ public class IndexCPPBindingResolutionBugs extends IndexBindingResolutionTestBas
public SingleProject() {setStrategy(new SinglePDOMTestStrategy(true));}
public static TestSuite suite() {return suite(SingleProject.class);}
}
public static class ProjectWithDepProj extends IndexCPPBindingResolutionBugs {
public ProjectWithDepProj() {setStrategy(new ReferencedProject(true));}
public static TestSuite suite() {return suite(ProjectWithDepProj.class);}
}
public static void addTests(TestSuite suite) {
suite.addTest(IndexCPPBindingResolutionBugsSingleProjectFirstAST.suite());
suite.addTest(SingleProject.suite());
suite.addTest(ProjectWithDepProj.suite());
}
@ -87,6 +88,7 @@ public class IndexCPPBindingResolutionBugs extends IndexBindingResolutionTestBas
// #define FUNC() void bar()
// #define FUNC2(A) void baz()
// #include "header.h"
//
// OBJ {}
@ -1136,4 +1138,20 @@ public class IndexCPPBindingResolutionBugs extends IndexBindingResolutionTestBas
buf.append('}');
return buf.toString();
}
// class Derived;
// class X {
// Derived* d;
// };
// class Base {};
// void useBase(Base* b);
// class Derived: Base {};
// void test() {
// X x;
// useBase(x.d);
// }
public void testLateDefinitionOfInheritance_Bug292749() throws Exception {
getBindingFromASTName("useBase(x.d", 7, ICPPFunction.class);
}
}

View file

@ -0,0 +1,25 @@
/*******************************************************************************
* 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.index.tests;
import junit.framework.TestSuite;
public class IndexCPPBindingResolutionBugsSingleProjectFirstAST extends IndexCPPBindingResolutionBugs {
public IndexCPPBindingResolutionBugsSingleProjectFirstAST() {
setStrategy(new SinglePDOMTestFirstASTStrategy(true));
}
public static TestSuite suite() {return suite(IndexCPPBindingResolutionBugsSingleProjectFirstAST.class);}
// invalid tests for this strategy, they assume that the second file is already indexed.
@Override public void testBug208558() {}
@Override public void testBug176708_CCE() {}
@Override public void testIsSameAnonymousType_Bug193962() {}
@Override public void testIsSameNestedAnonymousType_Bug193962() {}
}

View file

@ -35,6 +35,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguityParent;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
* @author jcamelon
@ -188,11 +189,11 @@ public class CPPASTFieldReference extends ASTNode implements
IBinding binding = name.resolvePreBinding();
try {
if (binding instanceof IVariable) {
return ((IVariable) binding).getType();
return SemanticUtil.mapToAST(((IVariable) binding).getType(), this);
} else if (binding instanceof IEnumerator) {
return ((IEnumerator) binding).getType();
} else if (binding instanceof IFunction) {
return ((IFunction) binding).getType();
return SemanticUtil.mapToAST(((IFunction) binding).getType(), this);
} else if (binding instanceof ICPPUnknownBinding) {
return CPPUnknownClass.createUnnamedInstance();
} else if (binding instanceof IProblemBinding) {

View file

@ -213,9 +213,9 @@ public class CPPASTFunctionCallExpression extends ASTNode implements
return new ProblemBinding(this, IProblemBinding.SEMANTIC_BAD_SCOPE,
binding.getName().toCharArray());
} else if (binding instanceof IFunction) {
t = ((IFunction) binding).getType();
t = SemanticUtil.mapToAST(((IFunction) binding).getType(), this);
} else if (binding instanceof IVariable) {
t = ((IVariable) binding).getType();
t = SemanticUtil.mapToAST(((IVariable) binding).getType(), this);
} else if (binding instanceof IType) {
return (IType) binding; // constructor or simple type initializer
} else if (binding instanceof IProblemBinding) {

View file

@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateNonTypeParameter;
import org.eclipse.cdt.internal.core.dom.parser.ASTNode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
/**
* @author jcamelon
@ -91,13 +92,13 @@ public class CPPASTIdExpression extends ASTNode implements IASTIdExpression, IAS
IBinding binding = name.resolvePreBinding();
try {
if (binding instanceof IVariable) {
return ((IVariable) binding).getType();
return SemanticUtil.mapToAST(((IVariable) binding).getType(), this);
} else if (binding instanceof IEnumerator) {
return ((IEnumerator) binding).getType();
} else if (binding instanceof IProblemBinding) {
return (IType) binding;
} else if (binding instanceof IFunction) {
return ((IFunction) binding).getType();
return SemanticUtil.mapToAST(((IFunction) binding).getType(), this);
} else if (binding instanceof ICPPTemplateNonTypeParameter) {
return ((ICPPTemplateNonTypeParameter) binding).getType();
} else if (binding instanceof ICPPClassType) {

View file

@ -17,6 +17,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
@ -194,10 +195,20 @@ class BaseClassLookup {
// 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) {
HashSet<IBinding> grandBaseBindings= null;
BitSet selectedBases= null;
if (grandBases.length > 1) {
grandBaseBindings= new HashSet<IBinding>();
// if we have reachable bases, then ignore the others
selectedBases = selectPreferredBases(data, grandBases);
}
for (int i = 0; i < grandBases.length; i++) {
ICPPBase grandBase = grandBases[i];
if (grandBase instanceof IProblemBinding)
continue;
if (selectedBases != null && !selectedBases.get(i))
continue;
try {
IBinding grandBaseBinding = grandBase.getBaseClass();
@ -238,6 +249,31 @@ class BaseClassLookup {
return result;
}
private static BitSet selectPreferredBases(LookupData data, ICPPBase[] grandBases) {
if (data.contentAssist)
return null;
BitSet selectedBases;
selectedBases= new BitSet(grandBases.length);
IName baseName= null;
for (int i = 0; i < grandBases.length; i++) {
ICPPBase nbase = grandBases[i];
if (nbase instanceof IProblemBinding)
continue;
final IName nbaseName = nbase.getBaseClassSpecifierName();
int cmp= baseName == null ? -1 : CPPSemantics.compareByRelevance(data, baseName, nbaseName);
if (cmp <= 0) {
if (cmp < 0) {
selectedBases.clear();
baseName= nbaseName;
}
selectedBases.set(i);
}
}
return selectedBases;
}
static void hideVirtualBases(BaseClassLookup rootInfo, HashMap<IScope, BaseClassLookup> infoMap) {
boolean containsVirtualBase= false;
final BaseClassLookup[] allInfos = infoMap.values().toArray(new BaseClassLookup[infoMap.size()]);

View file

@ -24,6 +24,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.cdt.core.dom.IName;
import org.eclipse.cdt.core.dom.ast.ASTNodeProperty;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
import org.eclipse.cdt.core.dom.ast.DOMException;
@ -136,7 +137,9 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.index.IIndexBinding;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexFileSet;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.parser.IProblem;
import org.eclipse.cdt.core.parser.util.ArrayUtil;
import org.eclipse.cdt.core.parser.util.CharArrayObjectMap;
@ -183,6 +186,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions.UDCMode;
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Cost.Rank;
import org.eclipse.cdt.internal.core.index.IIndexScope;
import org.eclipse.core.runtime.CoreException;
/**
* Name resolution
@ -1788,6 +1792,36 @@ public class CPPSemantics {
return 0;
}
/**
* Compares two bindings for relevance in the context of an AST. AST bindings are
* considered more relevant than index ones since the index may be out of date,
* built for a different configuration, etc. Index bindings reachable through includes
* are more relevant than unreachable ones.
* @param ast
* @param b1
* @param b2
* @return 1 if binding <code>b1</code> is more relevant than <code>b2</code>; 0 if
* the two bindings have the same relevance; -1 if <code>b1</code> is less relevant than
* <code>b2</code>.
*/
static int compareByRelevance(LookupData data, IName b1, IName b2) {
boolean b1FromIndex= (b1 instanceof IIndexName);
boolean b2FromIndex= (b2 instanceof IIndexName);
if (b1FromIndex != b2FromIndex) {
return !b1FromIndex ? 1 : -1;
} else if (b1FromIndex) {
// Both are from index.
if (data.tu != null) {
boolean b1Reachable= isReachableFromAst(data.tu, b1);
boolean b2Reachable= isReachableFromAst(data.tu, b2);
if (b1Reachable != b2Reachable) {
return b1Reachable ? 1 : -1;
}
}
}
return 0;
}
/**
* Compares a binding with a list of function candidates for relevance in the context of an AST. AST bindings are
* considered more relevant than index ones since the index may be out of date,
@ -1864,6 +1898,28 @@ public class CPPSemantics {
return indexFileSet != null && indexFileSet.containsDeclaration(indexBinding);
}
/**
* Checks if a binding is an AST binding, or is reachable from the AST through includes.
* The binding is assumed to belong to the AST, if it is not an IIndexBinding and not
* a specialization of an IIndexBinding.
* @param ast
* @param binding
* @return <code>true</code> if the <code>binding</code> is reachable from <code>ast</code>.
*/
private static boolean isReachableFromAst(IASTTranslationUnit ast, IName name) {
if (!(name instanceof IIndexName)) {
return true;
}
IIndexName indexName = (IIndexName) name;
try {
IIndexFile file= indexName.getFile();
IIndexFileSet indexFileSet = ast.getIndexFileSet();
return indexFileSet != null && indexFileSet.contains(file);
} catch (CoreException e) {
return false;
}
}
static private void reduceToViable(LookupData data, IBinding[] functions) throws DOMException {
if (functions == null || functions.length == 0)
return;
@ -2452,7 +2508,7 @@ public class CPPSemantics {
* Also collections the function bindings if requested.
*/
public static IType getChainedMemberAccessOperatorReturnType(ICPPASTFieldReference fieldReference, Collection<ICPPFunction> functionBindings) throws DOMException {
IASTExpression owner = fieldReference.getFieldOwner();
final IASTExpression owner = fieldReference.getFieldOwner();
if (owner == null)
return null;
@ -2505,7 +2561,7 @@ public class CPPSemantics {
if (functionBindings != null)
functionBindings.add(op);
type= op.getType().getReturnType();
type= SemanticUtil.mapToAST(op.getType().getReturnType(), owner);
foundOperator= true;
}

View file

@ -594,9 +594,8 @@ public class Conversions {
}
}
// This should actually be done in 'checkImplicitConversionSequence', see 13.3.3.1-6 and 8.5.14
// 8.5.14 cv-qualifiers can be ignored for non-class types
// mstodo
// This should actually be done before the conversion is attempted, see for instance 13.3.3.1-6 and 8.5.14.
// However, it does not hurt to do it here either.
IType unqualifiedTarget= getNestedType(target, CVQ | PTR_CVQ | TDEF | REF);
if (!(unqualifiedTarget instanceof ICPPClassType)) {
IType unqualifiedSource= getNestedType(source, CVQ | PTR_CVQ | TDEF | REF);

View file

@ -15,6 +15,8 @@ package org.eclipse.cdt.internal.core.dom.parser.cpp.semantics;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IArrayType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IFunctionType;
@ -37,6 +39,7 @@ import org.eclipse.cdt.core.parser.util.CharArraySet;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.core.parser.util.ObjectSet;
import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
@ -44,6 +47,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPTemplateArgument;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPDeferredClassInstance;
import org.eclipse.cdt.internal.core.dom.parser.cpp.OverloadableOperator;
import org.eclipse.cdt.internal.core.index.IIndexType;
/**
*
@ -290,6 +294,42 @@ public class SemanticUtil {
type.setType(newNestedType);
return type;
}
public static IType mapToAST(IType type, IASTNode node) {
if (!(type instanceof IIndexType))
return type;
try {
if (type instanceof IFunctionType) {
final ICPPFunctionType ft = (ICPPFunctionType) type;
final IType r = ft.getReturnType();
final IType ret = mapToAST(r, node);
if (ret == r) {
return type;
}
return new CPPFunctionType(ret, ft.getParameterTypes(), ft.isConst(), ft.isVolatile());
}
if (type instanceof ITypeContainer) {
final ITypeContainer tc = (ITypeContainer) type;
final IType nestedType= tc.getType();
if (nestedType == null)
return type;
IType newType= mapToAST(nestedType, node);
if (newType != nestedType) {
return replaceNestedType(tc, newType);
}
return type;
} else if (type instanceof ICPPClassType && type instanceof IIndexType) {
IASTTranslationUnit tu = node.getTranslationUnit();
if (tu instanceof CPPASTTranslationUnit) {
return ((CPPASTTranslationUnit) tu).mapToAST((ICPPClassType) type);
}
}
} catch (DOMException e) {
}
return type;
}
public static IType[] getSimplifiedTypes(IType[] types) {
// Don't create a new array until it's really needed.