/******************************************************************************* * Copyright (c) 2012, 2015 Google, 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: * Sergey Prigogin (Google) - initial API and implementation *******************************************************************************/ package org.eclipse.cdt.ui.tests.refactoring.includes; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.eclipse.jface.preference.IPreferenceStore; import com.ibm.icu.text.MessageFormat; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding; import org.eclipse.cdt.core.index.IIndex; import org.eclipse.cdt.core.index.IIndexManager; import org.eclipse.cdt.core.model.ITranslationUnit; import org.eclipse.cdt.core.parser.util.StringUtil; import org.eclipse.cdt.core.testplugin.util.OneSourceMultipleHeadersTestCase; import org.eclipse.cdt.core.testplugin.util.TestSourceReader; import org.eclipse.cdt.ui.CUIPlugin; import org.eclipse.cdt.ui.PreferenceConstants; import org.eclipse.cdt.ui.testplugin.CTestPlugin; import org.eclipse.cdt.internal.ui.refactoring.includes.BindingClassifier; import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeCreationContext; import junit.framework.TestSuite; /** * Tests for {@link BindingClassifier}. */ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase { private IIndex fIndex; private BindingClassifier fBindingClassifier; public BindingClassifierTest() { super(new TestSourceReader(CTestPlugin.getDefault().getBundle(), "ui", BindingClassifierTest.class), true); } public static TestSuite suite() { return suite(BindingClassifierTest.class); } @Override protected void setUp() throws Exception { super.setUp(true); IASTTranslationUnit ast = getAst(); fIndex = CCorePlugin.getIndexManager().getIndex(getCProject(), IIndexManager.ADD_DEPENDENCIES | IIndexManager.ADD_EXTENSION_FRAGMENTS_ADD_IMPORT); fIndex.acquireReadLock(); IPreferenceStore preferenceStore = getPreferenceStore(); preferenceStore.setToDefault(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS); } private void classifyBindings() { if (fBindingClassifier == null) { IASTTranslationUnit ast = getAst(); ITranslationUnit tu = ast.getOriginatingTranslationUnit(); IncludeCreationContext context = new IncludeCreationContext(tu, fIndex); fBindingClassifier = new BindingClassifier(context); fBindingClassifier.classifyNodeContents(ast); } } @Override protected void tearDown() throws Exception { fIndex.releaseReadLock(); fBindingClassifier = null; super.tearDown(); } private IPreferenceStore getPreferenceStore() { return CUIPlugin.getDefault().getPreferenceStore(); } private void assertDefined(String... names) throws Exception { classifyBindings(); assertExpectedBindings(names, fBindingClassifier.getBindingsToDefine(), "defined"); } private void assertDeclared(String... names) throws Exception { classifyBindings(); assertExpectedBindings(names, fBindingClassifier.getBindingsToForwardDeclare(), "declared"); } private void assertExpectedBindings(String[] expectedNames, Set<IBinding> bindings, String verb) throws Exception { Set<String> expected = new TreeSet<>(Arrays.asList(expectedNames)); Set<String> extra = new TreeSet<>(); for (IBinding binding : bindings) { extra.add(getQualifiedName(binding)); } Set<String> missing = new TreeSet<>(expected); missing.removeAll(extra); extra.removeAll(expected); if (extra.isEmpty() && missing.isEmpty()) return; List<String> errors = new ArrayList<>(2); if (!missing.isEmpty()) { errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" {0,choice,1#is|1<are} not {2}.", missing.size(), StringUtil.join(missing, "\", \""), verb)); } if (!extra.isEmpty()) { errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" should not be {2}.", extra.size(), StringUtil.join(extra, "\", \""), verb)); } fail(StringUtil.join(errors, " ")); } protected String getQualifiedName(IBinding binding) throws DOMException { if (binding instanceof ICPPBinding) { return StringUtil.join(((ICPPBinding) binding).getQualifiedName(), "::"); } else { return binding.getName(); } } // class A; // typedef A* td1; // typedef td1* td2; // td2 f(); // A* a = *f(); public void testTypedef_1() throws Exception { assertDefined("f"); assertDeclared("A"); } // class A; // typedef A* td1; // typedef td1* td2; // td2 f(); // td1 a = *f(); public void testTypedef_2() throws Exception { assertDefined("f", "td1"); assertDeclared(); } // template<typename T> struct allocator {}; // template<typename T, typename U = allocator<T>> class basic_string {}; // typedef basic_string<char> string; // template<typename T, typename A> // basic_string<T, A> f(const T* a, const basic_string<T, A>& b); // void test() { // string a; // f("*", a); // } public void testTypedef_3() throws Exception { assertDefined("f", "string"); // "basic_string" and "allocator" should not be defined. assertDeclared(); } // struct A { int x; }; // typedef A* td; // td f(); // int a = f()->x; public void testClassMember() throws Exception { assertDefined("A", "f"); assertDeclared(); } // struct A { void m(); }; // class B : public A {}; // B b; // class C : public A {}; // C* c; // void test() { // b.m(); // c->m(); // } public void testClassHierarchy() throws Exception { assertDefined("B", "b", "C", "c", "A::m"); assertDeclared(); } // class A { void m(); }; // void test(A* a) { // a->m(); // } public void testMethodCall() throws Exception { assertDefined("A", "A::m"); assertDeclared(); } // struct A { // void a() const; // }; // struct B : public A { // } // struct C { // const B& c() const; // }; // void test(const C& x) { // x.c().a(); // } public void testMethodCall_488349() throws Exception { assertDefined("A::a", "B", "C", "C::c"); assertDeclared(); } // class Base { // public: // void m(); // }; // // class Derived : public Base { // }; // class Derived; // void test(Derived& d) { // d.m(); // } public void testSuperClassMethodCall_436656() throws Exception { assertDefined("Derived", "Base::m"); assertDeclared(); } // class A {}; // void f(const A* p); // A* g(); // void test() { // f(g()); // f(0); // f(nullptr); // } public void testFunctionCallWithPointerParameter_1() throws Exception { getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true); assertDefined(); assertDeclared("A", "f", "g"); } // typedef int A; // void f(const A* p) {} // void test() { // f(nullptr); // } public void testFunctionCallWithPointerParameter_2() throws Exception { getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true); assertDefined("f"); // Inline definition has to be included. assertDeclared(); } // class A {}; // void f(const A& p); // A& g(); // void test() { // f(g()); // } public void testFunctionCallWithReferenceParameter() throws Exception { getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true); assertDefined(); assertDeclared("A", "f", "g"); } // struct A { // A(const char* s); // }; // void f(A p); // void test() { // f(""); // } public void testFunctionCallWithTypeConversion_1() throws Exception { // A header declaring the function is responsible for defining the parameter type that // provides constructor that can be used for implicit conversion. assertDefined("f"); assertDeclared(); } // struct A {}; // struct B { operator A(); }; // void f(A p); // void test(B b) { // f(b); // } public void testFunctionCallWithTypeConversion_2() throws Exception { // A header declaring the function is not responsible for defining the parameter type since // the implicit conversion from B to A is provided externally to parameter type. assertDefined("A", "B", "f"); assertDeclared(); } // typedef int int32; // void f(int32* p); // void test(int i) { // f(&i); // } public void testFunctionCallWithTypedef() throws Exception { getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, false); assertDefined("f"); assertDeclared(); } // struct A { // A(void* p); // }; // void test() { // A(nullptr); // } public void testConstructorCall() throws Exception { getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true); assertDefined("A", "A::A"); assertDeclared(); } // struct A { // A(void* p); // }; // typedef A B; // void test() { // B(nullptr); // } public void testConstructorCallWithTypedef() throws Exception { getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true); assertDefined("B", "A::A"); assertDeclared(); } // struct A { // A(const B& b); // }; // struct B {}; // A f(B* b) { // return *b; // } public void testFunctionReturnType_1() throws Exception { assertDefined("A", "B"); assertDeclared(); } // class A; // A* f() { // return nullptr; // } public void testFunctionReturnType_2() throws Exception { assertDefined(); assertDeclared("A"); } // class A; // const A* f(A* a) { // return a; // } public void testFunctionReturnType_3() throws Exception { assertDefined(); assertDeclared("A"); } // class A { // void m(); // }; // void A::m() { // } public void testMethodDefinition() throws Exception { assertDefined("A"); assertDeclared(); } // class A {}; // class B {}; // class C {}; // class D {}; // void foo(A* a, B& b, C& c) { // A& aa(*a); // B* bb(&b); // C cc(c); // D d; // } public void testVariableDeclaration() throws Exception { assertDefined("C", "D"); assertDeclared("A", "B"); } // class A {}; // class B {}; // class C {}; // class D { // A* aa; // B& bb; // C cc; // D(A* a, B& b, C& c) // : aa(a), bb(b), cc(c) {} // }; public void testConstructorChainInitializer() throws Exception { assertDefined("C"); assertDeclared("A", "B"); } // class A {}; // class B : public A {}; // extern A* a; // extern B* b; // void test() { // a = { b }; // } public void testInitializerList_506529() throws Exception { assertDefined("B", "a", "b"); } // namespace ns1 { // namespace ns2 { // class A {}; // } // } // namespace ns = ns1::ns2; // ns::A a; public void testNamespaceAlias() throws Exception { assertDefined("ns1::ns2::A", "ns"); assertDeclared(); } // namespace ns { // class A {}; // } // using ns::A; public void testUsingDeclaration() throws Exception { assertDefined(); assertDeclared("ns::A"); } // struct A { // A(const char* s); // }; // struct B { // explicit B(const char* s); // }; // void f(A a, B b); public void testFunctionDeclarationWithTypeConversion() throws Exception { // A file declaring the function is responsible for defining the parameter type that // provides constructor that can be used for implicit conversion. assertDefined("A"); assertDeclared("B"); } // struct A {}; // struct B {}; // struct C { // A a; // static B b; // }; public void testFieldReference() throws Exception { assertDefined("A"); assertDeclared("B"); } // namespace std { // template<typename T> class shared_ptr {}; // } // // struct A { // int x; // }; // struct B { // const std::shared_ptr<A> y; // }; // int test(B* b) { // return b->y->x; // }; public void testFieldReference_487971() throws Exception { assertDefined("A", "B"); assertDeclared(); } // typedef unsigned int size_t; // size_t a; // void test() { // void* x = &a; // } public void testVariableReference() throws Exception { assertDefined("a"); // Forward declaration of variables is not allowed by default. assertDeclared(); } // struct A { // void operator()(int p); // }; // A a; // void test() { // a(1); // } public void testCallOperator() throws Exception { assertDefined("A", "a", "A::operator ()"); assertDeclared(); } // struct A { // int x; // }; // inline bool operator==(const A& a1, const A& a2) { // return a1.x == a2.x; // } // bool test(const A& a, const A& b) { // return a == b; // } public void testOverloadedOperator() throws Exception { assertDefined("operator =="); assertDeclared("A"); } // class A {}; // class B : public A {}; // void test(B* b) { // const A* a = b; // } public void testBaseClass() throws Exception { assertDefined("B"); assertDeclared(); } // class Base {}; // class Derived : public Base { // public: // Derived(); // }; public void testBaseClause_421398() throws Exception { assertDefined("Base"); assertDeclared(); } // struct A {}; // template<typename T> struct B {}; // template<typename T, typename U = B<T>> struct C {}; // struct D : public C<A> {}; public void testTemplate_1() throws Exception { assertDefined("A", "C"); assertDeclared(); } // struct A {}; // template<typename T> struct B {}; // template<typename T, typename U = B<T>> struct C {}; // struct D : public C<A> {}; // void test() { // D d; // } public void testTemplate_2() throws Exception { assertDefined("D"); assertDeclared(); } // namespace std { // template<typename T> class shared_ptr {}; // template<typename T> class unique_ptr {}; // } // class A {}; // class B {}; // class C {}; // using std::unique_ptr; // using std::shared_ptr; // // struct P { // ~P(); // shared_ptr<A> x; // unique_ptr<A> y; // }; // // struct Q { // ~Q() {} // shared_ptr<B> x; // unique_ptr<B> y; // }; // // void test() { // shared_ptr<C> x; // unique_ptr<C> y; // } public void testTemplatesAllowingIncompleteParameterType_1() throws Exception { assertDefined("B", "C", "std::shared_ptr", "std::unique_ptr"); assertDeclared("A"); } // namespace std { // template<typename T> // struct unique_ptr { // T* operator->(); // }; // } // struct A { // void m(); // }; // class B : public A { // }; // std::unique_ptr<B> b; // void test() { // b->m(); // } public void testTemplatesAllowingIncompleteParameterType_2() throws Exception { assertDefined("B", "b", "A::m"); assertDeclared(); } // namespace std { // template<typename T> // struct unique_ptr { // T* operator->(); // }; // } // struct A { // void m(); // }; // class B : public A { // }; // struct C { // std::unique_ptr<B> x; // }; // void test(C* c) { // c->x->m(); // } public void testTemplatesAllowingIncompleteParameterType_3() throws Exception { assertDefined("B", "C", "A::m"); assertDeclared(); } // namespace std { // template<typename T> // struct shared_ptr { // T* operator->(); // }; // } // struct A { // void m(); // }; // class B : public A { // }; // std::shared_ptr<B> f(); // void test() { // f()->m(); // } public void testTemplatesAllowingIncompleteParameterType_4() throws Exception { assertDefined("B", "f", "A::m"); assertDeclared(); } // namespace std { // template<typename T> // struct unique_ptr { // T* operator->(); // }; // } // struct A { // void m(); // }; // class B : public A { // }; // struct C { // std::unique_ptr<B> f(); // }; // void test(C* c) { // c->f()->m(); // } public void testTemplatesAllowingIncompleteParameterType_5() throws Exception { assertDefined("B", "C", "C::f", "A::m"); assertDeclared(); } // struct A {}; // auto lambda = [](A* a) { return *a; }; public void testLambdaExpression() throws Exception { assertDefined("A"); assertDeclared(); } // struct A { // void operator()(); // }; // struct B : public A { // }; // struct C { // B b; // }; // void test(C* c) { // c->b(); // } public void testFieldAccess_442841_1() throws Exception { assertDefined("C", "A::operator ()"); assertDeclared(); } // struct A { // void operator()(); // }; // struct B : public A { // }; // struct C { // B& b; // }; // void test(C* c) { // c->b(); // } public void testFieldAccess_442841_2() throws Exception { assertDefined("B", "C", "A::operator ()"); assertDeclared(); } // struct A {}; // struct B {}; // struct C {}; // struct prefixD {}; // #define MACRO(t1, v1, t2, v3, t4, v4) t1 v1; t2 b; C v3; prefix##t4 v4 // MACRO(A, a, B, c, D, d); public void testMacro_1() throws Exception { assertDefined("A", "B", "MACRO"); assertDeclared(); } // typedef int INT; // #define MACRO(x) extern INT x // MACRO(a); // INT b; public void testMacro_2() throws Exception { assertDefined("MACRO", "INT"); // INT has to be defined because it is used outside of MACRO. assertDeclared(); } // class A {}; // A f(); // #define MACRO(x) A x = f() // MACRO(a); public void testMacro_3() throws Exception { assertDefined("MACRO"); assertDeclared(); } // void f(int); // #define MACRO(name, arg) void name() { f(arg); } // int bar; // MACRO(foo, bar); public void testMacro_4() throws Exception { assertDefined("MACRO"); assertDeclared(); } // template <typename T> // void m(); // // #define MACRO(a) m<a>() // typedef int INT; // void test() { // MACRO(INT); // } public void testMacro_5() throws Exception { assertDefined("MACRO"); assertDeclared(); } // struct A { // A(int); // }; // // #define MACRO(a, b) A a(b) // void test(int x) { // MACRO(a, x); // } public void testMacro_6() throws Exception { assertDefined("MACRO"); assertDeclared(); } // #define bool bool // #define false false // bool b = false; public void testIdentityMacro_487972() throws Exception { assertDefined(); assertDeclared(); } }