1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-08 10:16:03 +02:00

183160 - fix for class implicits

This commit is contained in:
Andrew Ferguson 2007-04-20 11:29:57 +00:00
parent 72a57a2bbb
commit c7553e11bf
4 changed files with 460 additions and 83 deletions

View file

@ -9,12 +9,16 @@
* IBM Corporation - initial API and implementation
* Ed Swartz (Nokia)
* Markus Schorn (Wind River Systems)
* Andrew Ferguson (Symbian)
*******************************************************************************/
/*
* Created on Nov 29, 2004
*/
package org.eclipse.cdt.core.parser.tests.ast2;
import java.io.BufferedReader;
import java.io.StringReader;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
@ -1250,7 +1254,7 @@ public class AST2CPPTests extends AST2BaseTest {
public void testConstructors() throws Exception {
StringBuffer buffer = new StringBuffer();
buffer.append("class A { A(); A( const A & ); }; "); //$NON-NLS-1$
buffer.append("class A { A(void); A( const A & ); }; "); //$NON-NLS-1$
IASTTranslationUnit tu = parse(buffer.toString(), ParserLanguage.CPP);
@ -1274,7 +1278,223 @@ public class AST2CPPTests extends AST2BaseTest {
assertTrue(qt.isConst());
assertSame(qt.getType(), A);
}
// class A {~A(); };
// class B {~B(void); };
public void testExplicitDestructor_183160() throws Exception {
// class F {(~)F(); };
// class G {(~)G(void); };
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPMethod[] methods = ((ICPPClassScope)A.getCompositeScope()).getImplicitMethods();
assertNotNull(methods);
int count=0;
for(int i=0; i<methods.length; i++)
count+= methods[i].getName().startsWith("~") ? 1 : 0;
assertEquals(line, 0, count);
methods = A.getDeclaredMethods();
assertNotNull(methods);
count=0;
for(int i=0; i<methods.length; i++)
count+= methods[i].getName().startsWith("~") ? 1 : 0;
assertEquals(line, 1, count);
}
}
// class C {};
// class D {D();};
// class E {E(void);};
public void testImplicitDestructor_183160() throws Exception {
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPMethod[] methods = ((ICPPClassScope)A.getCompositeScope()).getImplicitMethods();
assertNotNull(methods);
int count=0;
for(int i=0; i<methods.length; i++)
count+= methods[i].getName().startsWith("~") ? 1 : 0;
assertEquals(line, 1, count);
methods = A.getDeclaredMethods();
assertNotNull(methods);
count=0;
for(int i=0; i<methods.length; i++)
count+= methods[i].getName().startsWith("~") ? 1 : 0;
assertEquals(line, 0, count);
}
}
// class A {public: A();};
// class B {public: B() {}};
// class C {public: C() {}};
// class D {public: D(void) {}};
// class E {protected: E();};
// class F {protected: F() {}};
// class G {protected: G() {}};
// class H {protected: H(void) {}};
// class I {private: I();};
// class J {private: J() {}};
// class K {private: K() {}};
// class L {private: L(void) {}};
// class M {M();};
// class N {N() {}};
// class O {O() {}};
// class P {P(void) {}};
// class Q {public: Q(int k=5);};
// class R {public: R(int k=5, long k=4);};
// class S {public: S(int k=5, int* ip= 0);};
// class T {public: T(int k=5, int* ip= 0, T* t= 0);};
public void testExplicitDefaultConstructor_183160() throws Exception {
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPConstructor[] ctors = A.getConstructors();
assertNotNull(ctors);
assertEquals(2, ctors.length); // one user-declared default constructor, one implicit copy constructor
}
}
// class Q {public: Q(int k);};
// class R {public: R(int k=5, long k);};
// class S {public: S(int k=5, int* ip);};
// class T {public: T(int k, int* ip= 0, T* t= 0);};
public void testExplicitNonDefaultConstructor_183160() throws Exception {
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPConstructor[] ctors = A.getConstructors();
assertNotNull(ctors);
assertEquals(2, ctors.length); // one user-declared non-default constructor, one implicit copy constructor
}
}
// class A {public: A(A &);};
// class B {private: B(const B &);};
// class C {protected: C(volatile C &);};
// class D {D(const volatile D &) {}};
// class E {public: E(E &, int k=5);};
// class F {private: F(const F &, int j=2, int k=3);};
// class G {protected: G(volatile G &, int i=4, int l=2);};
// class H {H(const volatile H &, int i=1, long k=2) {}};
public void testExplicitCopyConstructor_183160() throws Exception {
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPConstructor[] ctors = A.getConstructors();
assertNotNull(ctors);
// one copy constructor, no implicit default constructor
assertEquals(1, ctors.length);
}
}
// class I {public: I(I *, int k=5);}; // I * rather than I &
// class J {private: J(const J *, int j, int k=3);}; // J * rather than J &
// class K {protected: K(volatile K *, int i=4, int l=2);}; // K * rather than K &
// class L {L(const volatile L &, int i=1, long k=2, int* x) {}}; // param int* x has no initializer
public void testNotExplicitCopyConstructor_183160() throws Exception {
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPConstructor[] ctors = A.getConstructors();
assertNotNull(ctors);
// one copy constructor, one user declared constructor (not a copy constructor)
assertEquals(2, ctors.length);
}
}
// class A {public: void operator=(int); }; // legitimate, but not a copy assignment operator
// class B {public: void operator=(B &, int); }; // compile error
// class C {public: void operator=(C &c, int k=5) {} }; // compile error
// class D {public: void operator=(const D &, const D &); }; // compile error
public void testNotExplicitCopyAssignmentOperator_183160() throws Exception {
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPMethod[] methods = ((ICPPClassScope)A.getCompositeScope()).getImplicitMethods();
assertNotNull(methods);
int count=0;
for(int i=0; i<methods.length; i++) {
boolean eq= Arrays.equals(methods[i].getName().toCharArray(), ICPPASTOperatorName.OPERATOR_ASSIGN);
count+= eq ? 1 : 0;
}
assertEquals(1, count); // check for one implicit operator= method
methods = A.getDeclaredMethods();
assertNotNull(methods);
count=0;
for(int i=0; i<methods.length; i++) {
boolean eq= Arrays.equals(methods[i].getName().toCharArray(), ICPPASTOperatorName.OPERATOR_ASSIGN);
count+= eq ? 1 : 0;
}
assertEquals(1, count); // check for the user declared
}
}
// class A {public: void operator=(A &); };
// class B {protected: void operator=(const B &); };
// class C {private: void operator=(volatile C &) {} };
// class D {D& operator=(volatile const D &); };
public void testExplicitCopyAssignmentOperator_183160() throws Exception {
BufferedReader br= new BufferedReader(new StringReader(getContents(1)[0].toString()));
for(String line= br.readLine(); line!=null; line= br.readLine()) {
IASTTranslationUnit tu = parse(line, ParserLanguage.CPP);
IASTSimpleDeclaration decl = (IASTSimpleDeclaration) tu.getDeclarations()[0];
IASTCompositeTypeSpecifier compSpec = (IASTCompositeTypeSpecifier) decl.getDeclSpecifier();
ICPPClassType A = (ICPPClassType) compSpec.getName().resolveBinding();
ICPPMethod[] methods = ((ICPPClassScope)A.getCompositeScope()).getImplicitMethods();
assertNotNull(methods);
int count=0;
for(int i=0; i<methods.length; i++) {
boolean eq= Arrays.equals(methods[i].getName().toCharArray(), ICPPASTOperatorName.OPERATOR_ASSIGN);
count+= eq ? 1 : 0;
}
assertEquals(0, count); // check for no implicit operator= methods
methods = A.getDeclaredMethods();
assertNotNull(methods);
count=0;
for(int i=0; i<methods.length; i++) {
boolean eq= Arrays.equals(methods[i].getName().toCharArray(), ICPPASTOperatorName.OPERATOR_ASSIGN);
count+= eq ? 1 : 0;
}
assertEquals(1, count); // only should get the user declared
}
}
public void testNamespaceAlias() throws Exception {
StringBuffer buffer = new StringBuffer();
buffer.append("namespace A { int x; } \n"); //$NON-NLS-1$
@ -4256,8 +4476,8 @@ public class AST2CPPTests extends AST2BaseTest {
.resolveBinding();
ICPPConstructor[] ctors = A.getConstructors();
assertEquals(ctors.length, 2);
assertSame(ctor, ctors[0]);
assertEquals(2, ctors.length); // one user declared constructor, one copy constructor
assertSame(ctor, ctors[1]);
tu = parse("class A { A( void ); };", ParserLanguage.CPP); //$NON-NLS-1$
col = new CPPNameCollector();
@ -4267,8 +4487,8 @@ public class AST2CPPTests extends AST2BaseTest {
ctor = (ICPPConstructor) col.getName(1).resolveBinding();
ctors = A.getConstructors();
assertEquals(ctors.length, 2);
assertSame(ctor, ctors[0]);
assertEquals(2, ctors.length); // one user declared constructor, one copy constructor
assertSame(ctor, ctors[1]);
}
public void testBug95461() throws Exception {

View file

@ -21,6 +21,7 @@ import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IField;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope;
@ -30,7 +31,6 @@ import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.internal.core.CCoreInternals;
import org.eclipse.cdt.internal.core.pdom.PDOM;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMName;
import org.eclipse.core.runtime.NullProgressMonitor;
/**
* @author Doug Schaefer
@ -57,7 +57,7 @@ public class ClassTests extends PDOMTestBase {
}
public void test1() throws Exception {
IBinding[] Bs = pdom.findBindings(Pattern.compile("B"), false, new IndexFilter(), new NullProgressMonitor());
IBinding[] Bs = pdom.findBindings(Pattern.compile("B"), false, IndexFilter.ALL, NPM);
assertEquals(1, Bs.length);
ICPPClassType B = (ICPPClassType)Bs[0];
ICPPMethod[] Bmethods = B.getAllDeclaredMethods();
@ -71,7 +71,7 @@ public class ClassTests extends PDOMTestBase {
}
public void testNested() throws Exception {
IBinding[] bindings = pdom.findBindings(Pattern.compile("NestedA"), false, new IndexFilter(), new NullProgressMonitor());
IBinding[] bindings = pdom.findBindings(Pattern.compile("NestedA"), false, IndexFilter.ALL, NPM);
assertEquals(1, bindings.length);
ICPPClassType NestedA = (ICPPClassType)bindings[0];
ICPPClassType[] nested = NestedA.getNestedClasses();
@ -94,7 +94,7 @@ public class ClassTests extends PDOMTestBase {
}
public void test147903() throws Exception {
IBinding[] bindings = pdom.findBindings(Pattern.compile("pr147903"), false, new IndexFilter(), new NullProgressMonitor());
IBinding[] bindings = pdom.findBindings(Pattern.compile("pr147903"), false, IndexFilter.ALL, NPM);
assertEquals(1, bindings.length);
ICPPNamespaceScope ns = ((ICPPNamespace)bindings[0]).getNamespaceScope();
bindings = ns.find("testRef");
@ -108,28 +108,28 @@ public class ClassTests extends PDOMTestBase {
/* Test friend relationships between classes */
public void _testFriend() throws Exception {
//TODO this test is failing
IBinding[] bindings = pdom.findBindings(Pattern.compile("ClassA"), false, new IndexFilter(), new NullProgressMonitor());
IBinding[] bindings = pdom.findBindings(Pattern.compile("ClassA"), false, IndexFilter.ALL, NPM);
assertEquals(1, bindings.length);
ICPPClassType classA = (ICPPClassType) bindings[0];
IBinding[] friends = classA.getFriends();
assertEquals(1, friends.length);
bindings = pdom.findBindings(Pattern.compile("ClassC"), false, new IndexFilter(), new NullProgressMonitor());
bindings = pdom.findBindings(Pattern.compile("ClassC"), false, IndexFilter.ALL, NPM);
assertEquals(bindings[0], friends[0]); //ClassC is a friend class of ClassA
bindings = pdom.findBindings(Pattern.compile("ClassC"), false, new IndexFilter(), new NullProgressMonitor());
bindings = pdom.findBindings(Pattern.compile("ClassC"), false, IndexFilter.ALL, NPM);
assertEquals(1, bindings.length);
ICPPClassType classC = (ICPPClassType) bindings[0];
friends = classC.getFriends();
assertEquals(1, friends.length);
Pattern[] patterns = {Pattern.compile("ClassB"),Pattern.compile("functionB")};
bindings = pdom.findBindings(patterns, false, new IndexFilter(), new NullProgressMonitor());
bindings = pdom.findBindings(patterns, false, IndexFilter.ALL, NPM);
assertEquals(bindings[0], friends[0]); //functionB is a friend of ClassC
}
public void _testConstructor() throws Exception {
// the source does not define Class1, so it is no surprise that the test is failing.
//TODO PDOM doesn't have information on constructor
IBinding[] bindings = pdom.findBindings(Pattern.compile("Class1"), false, new IndexFilter(), new NullProgressMonitor());
IBinding[] bindings = pdom.findBindings(Pattern.compile("Class1"), false, IndexFilter.ALL, NPM);
assertEquals(2, bindings.length);
assertTrue(bindings[0] instanceof ICPPClassType);
assertTrue(bindings[1] instanceof ICPPMethod);
@ -143,7 +143,7 @@ public class ClassTests extends PDOMTestBase {
assertEquals(offset("constructor.cpp","Class1::Class1") + 8, loc.getNodeOffset()); //character offset
/* Member initialization */
bindings = pdom.findBindings(Pattern.compile("number"), false, new IndexFilter(), new NullProgressMonitor());
bindings = pdom.findBindings(Pattern.compile("number"), false, IndexFilter.ALL, NPM);
assertEquals(1, bindings.length);
IName[] refs = pdom.findNames(bindings[0], IIndex.FIND_REFERENCES);
@ -153,4 +153,32 @@ public class ClassTests extends PDOMTestBase {
assertEquals(bindings[0], ((PDOMName)refs[0]).resolveBinding());
}
public void testAbsenceOfDefaultConstructorWhenExplicitNonDefaultPresentA() throws Exception {
IndexFilter JUST_CONSTRUCTORS= new IndexFilter() {
public boolean acceptBinding(IBinding binding) {
return binding instanceof ICPPConstructor;
}
public boolean acceptImplicitMethods() {
return true;
}
};
IBinding[] bindings = pdom.findBindings(Pattern.compile("C"), false, JUST_CONSTRUCTORS, NPM);
// expecting C(int) and C(const C &)
assertEquals(2, bindings.length);
}
public void testAbsenceOfDefaultConstructorWhenExplicitNonDefaultPresentB() throws Exception {
IndexFilter JUST_CONSTRUCTORS= new IndexFilter() {
public boolean acceptBinding(IBinding binding) {
return binding instanceof ICPPConstructor;
}
public boolean acceptImplicitMethods() {
return true;
}
};
IBinding[] bindings = pdom.findBindings(Pattern.compile("D"), false, JUST_CONSTRUCTORS, NPM);
// expecting just D(D &)
assertEquals(1, bindings.length);
}
}

View file

@ -11,3 +11,13 @@ int main() {
B b;
b.f();
}
class C {
public:
C(int a) {}
};
class D {
public:
D(D &) {}
};

View file

@ -9,15 +9,18 @@
* IBM Corporation - initial API and implementation
* Markus Schorn (Wind River Systems)
* Bryan Wilkinson (QNX)
* Andrew Ferguson (Symbian)
*******************************************************************************/
/*
* Created on Nov 29, 2004
*/
package org.eclipse.cdt.internal.core.dom.parser.cpp;
import java.util.ArrayList;
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.IASTArrayDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
@ -36,9 +39,11 @@ import org.eclipse.cdt.core.dom.ast.IScope;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTOperatorName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
@ -81,7 +86,6 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
if( !(binding instanceof ICPPClassType ) )
return;
implicits = new ICPPMethod[4];
ICPPClassType clsType = (ICPPClassType) binding;
if( clsType instanceof ICPPClassTemplate ){
try {
@ -94,72 +98,43 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
char [] className = name.toCharArray();
IParameter [] voidPs = new IParameter [] { new CPPParameter( CPPSemantics.VOID_TYPE ) };
if( !hasNonStandardDefaultConstructor( compTypeSpec ) ) {
//default constructor: A(void)
ICPPMethod m = new CPPImplicitConstructor( this, className, voidPs );
implicits[0] = m;
addBinding( m );
}
//copy constructor: A( const A & )
IType pType = new CPPReferenceType( new CPPQualifierType( clsType, true, false ) );
IParameter [] ps = new IParameter [] { new CPPParameter( pType ) };
ICPPMethod m = new CPPImplicitConstructor( this, className, ps );
implicits[1] = m;
addBinding( m );
//copy assignment operator: A& operator = ( const A & )
IType refType = new CPPReferenceType( clsType );
m = new CPPImplicitMethod( this, ICPPASTOperatorName.OPERATOR_ASSIGN, refType, ps );
implicits[2] = m;
addBinding( m );
//destructor: ~A()
char [] dtorName = CharArrayUtils.concat( "~".toCharArray(), className ); //$NON-NLS-1$
m = new CPPImplicitMethod( this, dtorName, new CPPBasicType( IBasicType.t_unspecified, 0 ), voidPs );
implicits[3] = m;
addBinding( m );
}
private boolean hasNonStandardDefaultConstructor( ICPPASTCompositeTypeSpecifier compSpec ){
IASTDeclaration [] members = compSpec.getMembers();
char [] name = compSpec.getName().toCharArray();
IASTDeclarator dtor = null;
IASTDeclSpecifier spec = null;
for( int i = 0; i < members.length; i++ ){
if( members[i] instanceof IASTSimpleDeclaration ){
IASTDeclarator [] dtors = ((IASTSimpleDeclaration)members[i]).getDeclarators();
if( dtors.length == 0 || dtors.length > 1 )
continue;
dtor = dtors[0];
spec = ((IASTSimpleDeclaration)members[i]).getDeclSpecifier();
} else if( members[i] instanceof IASTFunctionDefinition ){
dtor = ((IASTFunctionDefinition)members[i]).getDeclarator();
spec = ((IASTFunctionDefinition)members[i]).getDeclSpecifier();
}
if( !(dtor instanceof ICPPASTFunctionDeclarator) || !(spec instanceof IASTSimpleDeclSpecifier) ||
((IASTSimpleDeclSpecifier)spec).getType() != IASTSimpleDeclSpecifier.t_unspecified ||
!CharArrayUtils.equals( dtor.getName().toCharArray(), name ) )
{
continue;
}
IASTParameterDeclaration [] ps = ((ICPPASTFunctionDeclarator)dtor).getParameters();
if( ps.length >= 1 ){
IASTDeclarator d = ps[0].getDeclarator();
IASTDeclSpecifier s = ps[0].getDeclSpecifier();
if( s instanceof IASTSimpleDeclSpecifier &&
((IASTSimpleDeclSpecifier)s).getType() == IASTSimpleDeclSpecifier.t_void &&
d.getPointerOperators().length == 0 && !(d instanceof IASTArrayDeclarator) )
{
continue; //A(void)
}
if( d.getInitializer() != null )
return true;
}
}
return false;
IType pType = new CPPReferenceType( new CPPQualifierType( clsType, true, false ) );
IParameter [] ps = new IParameter [] { new CPPParameter( pType ) };
int i= 0;
ImplicitsAnalysis ia= new ImplicitsAnalysis( compTypeSpec );
implicits= new ICPPMethod[ia.getImplicitsToDeclareCount()];
if( !ia.hasUserDeclaredConstructor() ) {
//default constructor: A(void)
ICPPMethod m = new CPPImplicitConstructor( this, className, voidPs );
implicits[i++]=m;
addBinding( m );
}
if( !ia.hasUserDeclaredCopyConstructor() ) {
//copy constructor: A( const A & )
ICPPMethod m = new CPPImplicitConstructor( this, className, ps );
implicits[i++]=m;
addBinding( m );
}
if( !ia.hasUserDeclaredCopyAssignmentOperator() ) {
//copy assignment operator: A& operator = ( const A & )
IType refType = new CPPReferenceType( clsType );
ICPPMethod m = new CPPImplicitMethod( this, ICPPASTOperatorName.OPERATOR_ASSIGN, refType, ps );
implicits[i++]=m;
addBinding( m );
}
if( !ia.hasUserDeclaredDestructor() ) {
//destructor: ~A()
char [] dtorName = CharArrayUtils.concat( "~".toCharArray(), className ); //$NON-NLS-1$
ICPPMethod m = new CPPImplicitMethod( this, dtorName, new CPPBasicType( IBasicType.t_unspecified, 0 ), voidPs );
implicits[i++]=m;
addBinding( m );
}
}
public IScope getParent() {
@ -390,3 +365,147 @@ public class CPPClassScope extends CPPScope implements ICPPClassScope {
}
}
}
/**
* Helps analyzis of the class declaration for user declared members relevent
* to deciding which implicit bindings to declare.
*/
class ImplicitsAnalysis {
private boolean hasUserDeclaredConstructor;
private boolean hasUserDeclaredCopyConstructor;
private boolean hasUserDeclaredCopyAssignmentOperator;
private boolean hasUserDeclaredDestructor;
ImplicitsAnalysis( ICPPASTCompositeTypeSpecifier compSpec ) {
ICPPASTFunctionDeclarator[] ctors= getUserDeclaredCtorOrDtor(compSpec, true);
hasUserDeclaredConstructor= ctors.length> 0;
hasUserDeclaredCopyConstructor= false;
hasUserDeclaredCopyAssignmentOperator= false;
hasUserDeclaredDestructor= getUserDeclaredCtorOrDtor(compSpec, false).length>0;
outer: for(int i=0; i<ctors.length; i++) {
ICPPASTFunctionDeclarator dcltor= ctors[i];
IASTParameterDeclaration [] ps = ((ICPPASTFunctionDeclarator)dcltor).getParameters();
if( ps.length >= 1 ){
if(paramHasTypeReferenceToTheAssociatedClassType(ps[0])) {
// and all remaining arguments have initializers
for(int j=1; j<ps.length; j++) {
if( ps[j].getDeclarator().getInitializer() == null ) {
continue outer;
}
}
hasUserDeclaredCopyConstructor= true;
}
}
}
boolean hasUserDeclaredCAO= getUserDeclaredCopyAssignmentOperators(compSpec).length > 0;
hasUserDeclaredCopyAssignmentOperator= hasUserDeclaredCAO;
}
public int getImplicitsToDeclareCount() {
return (!hasUserDeclaredDestructor ? 1 : 0)
+ (!hasUserDeclaredConstructor ? 1 : 0)
+ (!hasUserDeclaredCopyConstructor ? 1 : 0)
+ (!hasUserDeclaredCopyAssignmentOperator ? 1 : 0);
}
private static ICPPASTFunctionDeclarator[] getUserDeclaredCtorOrDtor( ICPPASTCompositeTypeSpecifier compSpec, boolean constructor ) {
List result= new ArrayList();
IASTDeclaration [] members = compSpec.getMembers();
char [] name = compSpec.getName().toCharArray();
IASTDeclarator dcltor = null;
IASTDeclSpecifier spec = null;
for( int i = 0; i < members.length; i++ ){
if( members[i] instanceof IASTSimpleDeclaration ){
IASTDeclarator [] dtors = ((IASTSimpleDeclaration)members[i]).getDeclarators();
if( dtors.length == 0 || dtors.length > 1 )
continue;
dcltor = dtors[0];
spec = ((IASTSimpleDeclaration)members[i]).getDeclSpecifier();
} else if( members[i] instanceof IASTFunctionDefinition ){
dcltor = ((IASTFunctionDefinition)members[i]).getDeclarator();
spec = ((IASTFunctionDefinition)members[i]).getDeclSpecifier();
}
if( !(dcltor instanceof ICPPASTFunctionDeclarator) || !(spec instanceof IASTSimpleDeclSpecifier) ||
((IASTSimpleDeclSpecifier)spec).getType() != IASTSimpleDeclSpecifier.t_unspecified)
{
continue;
}
boolean nameEquals= false;
if(constructor) {
nameEquals= CharArrayUtils.equals( dcltor.getName().toCharArray(), name );
} else {
char[] cname= dcltor.getName().toCharArray();
if(cname.length>0 && cname[0]=='~') {
nameEquals= CharArrayUtils.equals( cname, 1, name.length, name );
}
}
if(!nameEquals)
continue;
result.add(dcltor);
}
return (ICPPASTFunctionDeclarator[]) result.toArray(new ICPPASTFunctionDeclarator[result.size()]);
}
private static ICPPASTFunctionDeclarator[] getUserDeclaredCopyAssignmentOperators( ICPPASTCompositeTypeSpecifier compSpec ) {
List result= new ArrayList();
IASTDeclaration [] members = compSpec.getMembers();
IASTDeclarator dcltor = null;
for( int i = 0; i < members.length; i++ ){
if( members[i] instanceof IASTSimpleDeclaration ){
IASTDeclarator [] dtors = ((IASTSimpleDeclaration)members[i]).getDeclarators();
if( dtors.length == 0 || dtors.length > 1 )
continue;
dcltor = dtors[0];
} else if( members[i] instanceof IASTFunctionDefinition ){
dcltor = ((IASTFunctionDefinition)members[i]).getDeclarator();
}
if( !(dcltor instanceof ICPPASTFunctionDeclarator) ||
!CharArrayUtils.equals( dcltor.getName().toCharArray(), ICPPASTOperatorName.OPERATOR_ASSIGN ) )
{
continue;
}
IASTParameterDeclaration [] ps = ((ICPPASTFunctionDeclarator)dcltor).getParameters();
if( ps.length != 1 || !paramHasTypeReferenceToTheAssociatedClassType(ps[0]) )
continue;
result.add(dcltor);
}
return (ICPPASTFunctionDeclarator[]) result.toArray(new ICPPASTFunctionDeclarator[result.size()]);
}
private static boolean paramHasTypeReferenceToTheAssociatedClassType(IASTParameterDeclaration dec) {
boolean result= false;
IASTDeclarator pdtor= dec.getDeclarator();
if(pdtor.getPointerOperators().length==1 && pdtor.getPointerOperators()[0] instanceof ICPPASTReferenceOperator) {
if(dec.getDeclSpecifier() instanceof ICPPASTNamedTypeSpecifier) {
result= true;
}
}
return result;
}
public boolean hasUserDeclaredConstructor() {
return hasUserDeclaredConstructor;
}
public boolean hasUserDeclaredCopyConstructor() {
return hasUserDeclaredCopyConstructor;
}
public boolean hasUserDeclaredCopyAssignmentOperator() {
return hasUserDeclaredCopyAssignmentOperator;
}
public boolean hasUserDeclaredDestructor() {
return hasUserDeclaredDestructor;
}
}