diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java index 1cd6d899fd5..e0c4666d931 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPImplicitNameTests.java @@ -7,6 +7,7 @@ * * Contributors: * Mike Kucera (IBM) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; @@ -16,8 +17,10 @@ import org.eclipse.cdt.core.dom.ast.IASTImplicitName; import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; import org.eclipse.cdt.core.parser.ParserLanguage; /** @@ -277,7 +280,7 @@ public class AST2CPPImplicitNameTests extends AST2BaseTest { // bool b = true; // x(b); // 1 // x(); // 2 - // x(1,2); // 3 + // x(1, 2); // 3 // } public void testFunctionCallOperator() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); @@ -301,7 +304,7 @@ public class AST2CPPImplicitNameTests extends AST2BaseTest { assertTrue(n2.isAlternate()); assertSame(col.getName(3).resolveBinding(), n1.resolveBinding()); - n1 = ba.assertImplicitName("(1,2); // 3", 1, ICPPMethod.class); + n1 = ba.assertImplicitName("(1, 2); // 3", 1, ICPPMethod.class); n2 = ba.assertImplicitName("); // 3", 1, ICPPMethod.class); assertSame(n1.resolveBinding(), n2.resolveBinding()); assertFalse(n1.isAlternate()); @@ -416,18 +419,18 @@ public class AST2CPPImplicitNameTests extends AST2BaseTest { // int test() { // X* fp = new (nothrow) X; // int* p = new (nothrow) int[5]; - // int* p2 = new (5,6) int[5]; + // int* p2 = new (5, 6) int[5]; // } public void testNew() throws Exception { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); IASTImplicitName n1 = ba.assertImplicitName("new (nothrow) X", 3, ICPPFunction.class); IASTImplicitName n2 = ba.assertImplicitName("new (nothrow) int", 3, ICPPFunction.class); - IASTImplicitName n3 = ba.assertImplicitName("new (5,6) int", 3, ICPPFunction.class); - + IASTImplicitName n3 = ba.assertImplicitName("new (5, 6) int", 3, ICPPFunction.class); + IASTTranslationUnit tu = ba.getTranslationUnit(); CPPNameCollector col = new CPPNameCollector(); tu.accept(col); - + assertSame(col.getName(4).resolveBinding(), n1.resolveBinding()); assertSame(col.getName(9).resolveBinding(), n2.resolveBinding()); assertSame(col.getName(14).resolveBinding(), n3.resolveBinding()); @@ -440,4 +443,56 @@ public class AST2CPPImplicitNameTests extends AST2BaseTest { BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); ba.assertNoImplicitName("throw;", 5); } + + // struct A { + // A() {} + // A(int) {} + // template + // A(T, int) {} + // }; + // typedef A B; + // + // void test() { + // B a; + // B b(1); + // B c = 1; + // B d("", 1); + // extern B e; + // } + // + // struct C { + // static B s = 1; + // static B t; + // B u; + // B v; + // C(int p) : u(), v(p) {} + // }; + // B C::t = 1; + public void testConstructorCall() throws Exception { + BindingAssertionHelper ba= new BindingAssertionHelper(getAboveComment(), true); + IASTTranslationUnit tu = ba.getTranslationUnit(); + ICPPConstructor ctor0 = ba.assertNonProblem("A()", 1, ICPPConstructor.class); + ICPPConstructor ctor1 = ba.assertNonProblem("A(int)", 1, ICPPConstructor.class); + ICPPConstructor ctor2 = ba.assertNonProblem("A(T, int)", 1, ICPPConstructor.class); + + IASTImplicitName a = ba.assertImplicitName("a;", 1, ICPPConstructor.class); + assertSame(ctor0, a.resolveBinding()); + IASTImplicitName b = ba.assertImplicitName("b(", 1, ICPPConstructor.class); + assertSame(ctor1, b.resolveBinding()); + IASTImplicitName c = ba.assertImplicitName("c =", 1, ICPPConstructor.class); + assertSame(ctor1, c.resolveBinding()); + IASTImplicitName d = ba.assertImplicitName("d(", 1, ICPPConstructor.class); + assertSame(ctor2, ((ICPPTemplateInstance) d.resolveBinding()).getTemplateDefinition()); + ba.assertNoImplicitName("e;", 1); + IASTImplicitName s = ba.assertImplicitName("s =", 1, ICPPConstructor.class); + assertSame(ctor1, s.resolveBinding()); + ba.assertNoImplicitName("t;", 1); + IASTImplicitName t = ba.assertImplicitName("t =", 1, ICPPConstructor.class); + assertSame(ctor1, t.resolveBinding()); + ba.assertNoImplicitName("u;", 1); + IASTImplicitName u = ba.assertImplicitName("u()", 1, ICPPConstructor.class); + assertSame(ctor0, u.resolveBinding()); + IASTImplicitName v = ba.assertImplicitName("v(p)", 1, ICPPConstructor.class); + assertSame(ctor1, v.resolveBinding()); + } } diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java index 6ff62bfae84..dc7aef3179c 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/index/tests/IndexNamesTests.java @@ -174,10 +174,11 @@ public class IndexNamesTests extends BaseTestCase { assertNull(main.getEnclosingDefinition()); IIndexName[] enclosed= main.getEnclosedNames(); - assertLength(3, enclosed); - assertName("C", enclosed[0]); - assertName("func", enclosed[1]); - assertName("var", enclosed[2]); + assertLength(4, enclosed); + assertName("C", enclosed[0]); // Class reference + assertName("C", enclosed[1]); // Implicit ctor call + assertName("func", enclosed[2]); + assertName("var", enclosed[3]); IIndexName enclosing= enclosed[0].getEnclosingDefinition(); assertNotNull(enclosing); @@ -189,9 +190,13 @@ public class IndexNamesTests extends BaseTestCase { enclosing= enclosed[2].getEnclosingDefinition(); assertNotNull(enclosing); + assertName("main", enclosing); + + enclosing= enclosed[3].getEnclosingDefinition(); + assertNotNull(enclosing); assertName("main", enclosing); - IIndexBinding funcB= fIndex.findBinding(enclosed[1]); + IIndexBinding funcB= fIndex.findBinding(enclosed[2]); assertNotNull(funcB); names= fIndex.findDefinitions(funcB); assertLength(1, names); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConstructorChainInitializer.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConstructorChainInitializer.java index 4cf646aa176..c6a267435f9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConstructorChainInitializer.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTConstructorChainInitializer.java @@ -8,6 +8,7 @@ * Contributors: * John Camelon (IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -16,6 +17,8 @@ import java.util.Arrays; import org.eclipse.cdt.core.dom.ast.ASTVisitor; import org.eclipse.cdt.core.dom.ast.IASTCompletionContext; import org.eclipse.cdt.core.dom.ast.IASTExpression; +import org.eclipse.cdt.core.dom.ast.IASTImplicitName; +import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; @@ -23,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding; 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.ICPPASTConstructorInitializer; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; @@ -40,8 +44,9 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; * {@code Base()} and {@code field()} are the constructor chain initializers.
*/ public class CPPASTConstructorChainInitializer extends ASTNode implements - ICPPASTConstructorChainInitializer, IASTCompletionContext { + ICPPASTConstructorChainInitializer, IASTImplicitNameOwner, IASTCompletionContext { private IASTName name; + private IASTImplicitName[] implicitNames; private IASTInitializer initializer; private boolean fIsPackExpansion; @@ -101,6 +106,13 @@ public class CPPASTConstructorChainInitializer extends ASTNode implements if (name != null && !name.accept(action)) return false; + if (action.shouldVisitImplicitNames) { + for (IASTImplicitName implicitName : getImplicitNames()) { + if (!implicitName.accept(action)) + return false; + } + } + if (initializer != null && !initializer.accept(action)) return false; @@ -154,7 +166,6 @@ public class CPPASTConstructorChainInitializer extends ASTNode implements for (IASTNode parent = name.getParent(); parent != null; parent = parent.getParent()) { if (parent instanceof ICPPASTCompositeTypeSpecifier) { ICPPASTCompositeTypeSpecifier specifier = (ICPPASTCompositeTypeSpecifier) parent; - return specifier.getBaseSpecifiers(); } } @@ -201,4 +212,27 @@ public class CPPASTConstructorChainInitializer extends ASTNode implements setInitializer(ctorInit); } } + + /** + * @see IASTImplicitNameOwner#getImplicitNames() + */ + public IASTImplicitName[] getImplicitNames() { + if (implicitNames == null) { + ICPPConstructor ctor = CPPSemantics.findImplicitlyCalledConstructor(this); + if (ctor == null) { + implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; + } else { + CPPASTImplicitName ctorName = new CPPASTImplicitName(ctor.getNameCharArray(), this); + ctorName.setBinding(ctor); + IASTName id = name; + if (id instanceof ICPPASTQualifiedName) { + id = ((ICPPASTQualifiedName) id).getLastName(); + } + ctorName.setOffsetAndLength((ASTNode) id); + implicitNames = new IASTImplicitName[] { ctorName }; + } + } + + return implicitNames; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java index f4c0df8cf9f..3c44dc15df0 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeclarator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2009 IBM Corporation and others. + * Copyright (c) 2004, 2010 IBM Corporation 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 @@ -8,6 +8,7 @@ * Contributors: * John Camelon (IBM) - Initial API and implementation * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; @@ -17,6 +18,8 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition; +import org.eclipse.cdt.core.dom.ast.IASTImplicitName; +import org.eclipse.cdt.core.dom.ast.IASTImplicitNameOwner; import org.eclipse.cdt.core.dom.ast.IASTInitializer; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; @@ -26,22 +29,26 @@ import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; import org.eclipse.cdt.core.dom.ast.IASTTypeId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; +import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; /** * C++ specific declarator. */ -public class CPPASTDeclarator extends ASTNode implements ICPPASTDeclarator { +public class CPPASTDeclarator extends ASTNode implements ICPPASTDeclarator, IASTImplicitNameOwner { private IASTInitializer initializer; private IASTName name; + private IASTImplicitName[] implicitNames; private IASTDeclarator nested; - private IASTPointerOperator[] pointerOps = null; + private IASTPointerOperator[] pointerOps; private boolean isPackExpansion; - + public CPPASTDeclarator() { } @@ -139,7 +146,7 @@ public class CPPASTDeclarator extends ASTNode implements ICPPASTDeclarator { switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; - default : break; + default: break; } } @@ -155,13 +162,19 @@ public class CPPASTDeclarator extends ASTNode implements ICPPASTDeclarator { if (nested == null && name != null) { IASTDeclarator outermost= ASTQueries.findOutermostDeclarator(this); if (outermost.getPropertyInParent() != IASTTypeId.ABSTRACT_DECLARATOR) { - if (!name.accept(action)) return false; + if (!name.accept(action)) + return false; + if (action.shouldVisitImplicitNames) { + for (IASTImplicitName implicitName : getImplicitNames()) { + if (!implicitName.accept(action)) + return false; + } + } } } - if (nested != null) { - if (!nested.accept(action)) return false; - } + if (nested != null && !nested.accept(action)) + return false; if (!postAccept(action)) return false; @@ -233,4 +246,27 @@ public class CPPASTDeclarator extends ASTNode implements ICPPASTDeclarator { } return false; } + + /** + * @see IASTImplicitNameOwner#getImplicitNames() + */ + public IASTImplicitName[] getImplicitNames() { + if (implicitNames == null) { + ICPPConstructor ctor = CPPSemantics.findImplicitlyCalledConstructor(this); + if (ctor == null) { + implicitNames = IASTImplicitName.EMPTY_NAME_ARRAY; + } else { + CPPASTImplicitName ctorName = new CPPASTImplicitName(ctor.getNameCharArray(), this); + ctorName.setBinding(ctor); + IASTName id = name; + if (id instanceof ICPPASTQualifiedName) { + id = ((ICPPASTQualifiedName) id).getLastName(); + } + ctorName.setOffsetAndLength((ASTNode) id); + implicitNames = new IASTImplicitName[] { ctorName }; + } + } + + return implicitNames; + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java index c8ef8bf04ad..d660215c315 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTDeleteExpression.java @@ -89,7 +89,7 @@ public class CPPASTDeleteExpression extends ASTNode implements ICPPASTDeleteExpr List names = new ArrayList(); if (!isVectored) { - ICPPFunction destructor = CPPSemantics.findDestructor(this); + ICPPFunction destructor = CPPSemantics.findImplicitlyCalledDestructor(this); if (destructor != null) { CPPASTImplicitName destructorName = new CPPASTImplicitName(destructor.getNameCharArray(), this); destructorName.setBinding(destructor); @@ -121,7 +121,7 @@ public class CPPASTDeleteExpression extends ASTNode implements ICPPASTDeleteExpr @Override public boolean accept(ASTVisitor action) { if (action.shouldVisitExpressions) { - switch(action.visit(this)) { + switch (action.visit(this)) { case ASTVisitor.PROCESS_ABORT: return false; case ASTVisitor.PROCESS_SKIP: return true; default: break; @@ -129,7 +129,7 @@ public class CPPASTDeleteExpression extends ASTNode implements ICPPASTDeleteExpr } if (action.shouldVisitImplicitNames) { - for(IASTImplicitName name : getImplicitNames()) { + for (IASTImplicitName name : getImplicitNames()) { if (!name.accept(action)) return false; } 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 5151a37d92c..be866f35f04 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 @@ -158,6 +158,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.IASTAmbiguousDeclarator; import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTDeclarator; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTFieldReference; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTLiteralExpression; @@ -2762,7 +2763,76 @@ public class CPPSemantics { return null; } - public static ICPPFunction findDestructor(ICPPASTDeleteExpression expr) { + /** + * Returns constructor called by a declarator, or null if no constructor is called. + */ + public static ICPPConstructor findImplicitlyCalledConstructor(CPPASTDeclarator declarator) { + if (declarator.getInitializer() == null) { + IASTNode parent = declarator.getParent(); + if (parent instanceof IASTSimpleDeclaration) { + IASTDeclSpecifier declSpec = ((IASTSimpleDeclaration) parent).getDeclSpecifier(); + parent = parent.getParent(); + if (parent instanceof IASTCompositeTypeSpecifier || + declSpec.getStorageClass() == IASTDeclSpecifier.sc_extern) { + // No initialization is performed for class members and extern declarations + // without an initializer. + return null; + } + } + } + return findImplicitlyCalledConstructor(declarator.getName(), declarator.getInitializer()); + } + + /** + * Returns constructor called by a class member initializer in a constructor initializer chain. + * Returns null if no constructor is called. + */ + public static ICPPConstructor findImplicitlyCalledConstructor(ICPPASTConstructorChainInitializer initializer) { + return findImplicitlyCalledConstructor(initializer.getMemberInitializerId(), initializer.getInitializer()); + } + + /** + * Returns constructor called by a variable declarator or an initializer in a constructor initializer + * chain. Returns null if no constructor is called. + */ + private static ICPPConstructor findImplicitlyCalledConstructor(IASTName name, IASTInitializer initializer) { + IBinding binding = name.resolveBinding(); + if (!(binding instanceof ICPPVariable)) + return null; + IType type; + try { + type = SemanticUtil.getSimplifiedType(((ICPPVariable) binding).getType()); + if (!(type instanceof ICPPClassType)) + return null; + ICPPClassType classType = (ICPPClassType) type; + CPPASTName astName = new CPPASTName(); + astName.setName(classType.getNameCharArray()); + astName.setOffsetAndLength((ASTNode) name); + CPPASTIdExpression idExp = new CPPASTIdExpression(astName); + idExp.setParent(name.getParent()); + idExp.setPropertyInParent(IASTFunctionCallExpression.FUNCTION_NAME); + + LookupData data = new LookupData(astName); + if (initializer == null) { + data.setFunctionArguments(IASTExpression.EMPTY_EXPRESSION_ARRAY); + } else if (initializer instanceof IASTEqualsInitializer) { + data.setFunctionArguments(((IASTEqualsInitializer) initializer).getInitializerClause()); + } else if (initializer instanceof ICPPASTConstructorInitializer) { + data.setFunctionArguments(((ICPPASTConstructorInitializer) initializer).getArguments()); + } else { + return null; + } + data.forceQualified = true; + data.foundItems = classType.getConstructors(); + binding = resolveAmbiguities(data, astName); + if (binding instanceof ICPPConstructor) + return (ICPPConstructor) binding; + } catch (DOMException e) { + } + return null; + } + + public static ICPPFunction findImplicitlyCalledDestructor(ICPPASTDeleteExpression expr) { ICPPClassType cls = getNestedClassType(expr); if (cls == null) return null;