diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index 711b2a1c96c..8725f485c90 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -32,6 +32,7 @@ import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.parser.ParserLanguage; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; @@ -3532,24 +3533,38 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { parse(getAboveComment(), ParserLanguage.CPP, false, 0); } - // struct B { - // virtual ~B() { } - // }; - // struct D : B { - // ~D() { } - // }; - // D D_object; - // typedef B B_alias; - // B* B_ptr = &D_object; - // void f() { - // D_object.B::~B(); // calls B's destructor - // B_ptr->~B(); //calls D's destructor - // B_ptr->~B_alias(); // calls D's destructor - // B_ptr->B_alias::~B(); // calls B's destructor - // B_ptr->B_alias::~B_alias(); // error, no B_alias in class B - // } + // struct B { + // virtual ~B() { } + // }; + // struct D : B { + // ~D() { } + // }; + // D D_object; + // typedef B B_alias; + // B* B_ptr = &D_object; + // void f() { + // D_object.B::~B(); //1 // calls B's destructor + // B_ptr->~B(); //2 // calls D's destructor + // B_ptr->~B_alias(); //3 // calls D's destructor + // B_ptr->B_alias::~B(); //4 // calls B's destructor + // B_ptr->B_alias::~B_alias(); //5 // error, no B_alias in class B + // } public void test12_4s12() throws Exception { - parse(getAboveComment(), ParserLanguage.CPP, false, 0); + final String code = getAboveComment(); + parse(code, ParserLanguage.CPP, false, 0); + BindingAssertionHelper bh= new BindingAssertionHelper(code, true); + ICPPFunction dtor= bh.assertNonProblem("~B() {", 2); + + ICPPFunction d= bh.assertNonProblem("~B(); //1", 2); + assertSame(dtor, d); + d= bh.assertNonProblem("~B(); //2", 2); + assertSame(dtor, d); + d= bh.assertNonProblem("~B_alias(); //3", 8); + assertSame(dtor, d); + d= bh.assertNonProblem("~B(); //4", 2); + assertSame(dtor, d); + + bh.assertProblem("~B_alias(); //5", 8); } // void* operator new(size_t, void* p) { return p; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 5d34b60b2e5..1c593ad5f3a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -165,6 +165,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTNameBase; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTQualifiedName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTranslationUnit; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTTypeIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTUnaryExpression; @@ -228,7 +229,7 @@ public class CPPSemantics { if (name instanceof CPPASTNameBase) { ((CPPASTNameBase) name).incResolutionDepth(); } - + // 1: get some context info off of the name to figure out what kind of lookup we want LookupData data = createLookupData(name, true); @@ -818,6 +819,10 @@ public class CPPSemantics { if (data.astName == null) return; + if (start == null && lookupDestructor(data, start)) { + return; + } + ICPPScope nextScope= null; ICPPTemplateScope nextTmplScope= null; if (start instanceof ICPPScope) { @@ -932,6 +937,81 @@ public class CPPSemantics { } } + private static boolean lookupDestructor(LookupData data, IScope start) throws DOMException { + IASTName typeDtorName= data.astName; + final char[] typeDtorChars= typeDtorName.getSimpleID(); + if (typeDtorChars.length == 0 || typeDtorChars[0] != '~') + return false; + + // Assume class C; typedef C T; + // When looking up ~T the strategy is to lookup T::~C in two steps: + // * First resolve 'T', then compute '~C' and resolve it. + CPPASTQualifiedName syntheticName= new CPPASTQualifiedName(); + IASTNode parent= typeDtorName.getParent(); + if (parent instanceof ICPPASTQualifiedName) { + ICPPASTQualifiedName dqname= (ICPPASTQualifiedName) parent; + if (dqname.getLastName() != data) + return false; + + syntheticName.setFullyQualified(dqname.isFullyQualified()); + IASTName[] children = dqname.getNames(); + for (IASTName child : children) { + if (child != data) { + final IASTName childCopy = child.copy(); + childCopy.setBinding(child.resolveBinding()); + syntheticName.addName(childCopy); + } + } + syntheticName.setOffsetAndLength((ASTNode) parent); + syntheticName.setParent(parent.getParent()); + syntheticName.setPropertyInParent(parent.getPropertyInParent()); + } else { + syntheticName.setOffsetAndLength((ASTNode) typeDtorName); + syntheticName.setParent(parent); + syntheticName.setPropertyInParent(typeDtorName.getPropertyInParent()); + } + char[] tchars= new char[typeDtorChars.length-1]; + System.arraycopy(typeDtorChars, 1, tchars, 0, tchars.length); + + final CPPASTName typeName = new CPPASTName(tchars); + typeName.setOffsetAndLength((ASTNode) typeDtorName); + syntheticName.addName(typeName); + + final CPPASTName classDtorName = new CPPASTName(typeDtorChars); + classDtorName.setOffsetAndLength((ASTNode) typeDtorName); + syntheticName.addName(classDtorName); + + IBinding type= resolveBinding(typeName); + if (!(type instanceof ITypedef)) + return false; + + IType t= SemanticUtil.getNestedType((ITypedef) type, TDEF); + if (t instanceof ICPPUnknownBinding || t instanceof IProblemBinding || + !(t instanceof ICPPClassType)) { + return false; + } + + ICPPClassType classType= (ICPPClassType) t; + final IScope scope = ((ICPPClassType) t).getCompositeScope(); + if (scope == null) { + return false; + } + + char[] classChars= classType.getNameCharArray(); + char[] classDtorChars= new char[classChars.length+1]; + classDtorChars[0]= '~'; + System.arraycopy(classChars, 0, classDtorChars, 1, classChars.length); + classDtorName.setName(classDtorChars); + + data.astName = classDtorName; + try { + lookup(data, scope); + } finally { + data.astName= typeDtorName; + } + return true; + } + /** * Checks whether the name directly or indirectly depends on the this pointer. */