blob: 800ae1308b7c3166a247c84f7a284b62cdb0ccc4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Nathan Ridge.
* 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
*******************************************************************************/
package org.eclipse.cdt.core.parser.tests.ast2.cxx14;
import org.eclipse.cdt.core.dom.ast.IProblemType;
import org.eclipse.cdt.core.dom.ast.IType;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.parser.tests.ast2.AST2CPPTestBase;
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPClosureType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPVariable;
public class ReturnTypeDeductionTests extends AST2CPPTestBase {
private void assertReturnType(String functionName, IType returnType) throws Exception {
BindingAssertionHelper bh = getAssertionHelper();
ICPPFunction f = bh.assertNonProblem(functionName);
assertSameType(f.getType().getReturnType(), returnType);
}
private void assertReturnTypeProblem(String functionName) throws Exception {
BindingAssertionHelper bh = getAssertionHelper();
ICPPFunction f = bh.assertNonProblem(functionName);
assertInstance(f.getType().getReturnType(), IProblemType.class);
}
private void assertLambdaReturnType(String lambdaName, IType returnType) throws Exception {
BindingAssertionHelper bh = getAssertionHelper();
ICPPVariable lambda = bh.assertNonProblem(lambdaName);
IType lambdaType = lambda.getType();
assertInstance(lambdaType, CPPClosureType.class);
ICPPFunction f = ((CPPClosureType) lambdaType).getFunctionCallOperator();
assertSameType(f.getType().getReturnType(), returnType);
}
// auto f() { return 42; }
public void testSingleReturn() throws Exception {
assertReturnType("f", CommonCPPTypes.int_);
}
// auto f(int x) {
// if (x < 10)
// return 42;
// else
// return 0;
// }
public void testMultipleReturnsSameType() throws Exception {
assertReturnType("f", CommonCPPTypes.int_);
}
// auto f(int x) {
// if (x < 10)
// return 42;
// else
// return 0.0;
// }
public void testMultipleReturnsDifferentTypes() throws Exception {
assertReturnTypeProblem("f");
}
// auto f() {
// return f();
// }
public void testFullyRecursiveFunction() throws Exception {
assertReturnTypeProblem("f");
}
// auto sum(int i) {
// if (i == 1)
// return i;
// else
// return sum(i - 1) + i;
// }
public void testPartiallyRecursiveFunction() throws Exception {
assertReturnType("sum", CommonCPPTypes.int_);
}
// template <typename T>
// auto f(T t) {
// return t;
// }
// typedef decltype(f(1)) fint_t;
public void testFunctionTemplate() throws Exception {
BindingAssertionHelper bh = getAssertionHelper();
ITypedef t = bh.assertNonProblem("fint_t");
assertSameType(t, CommonCPPTypes.int_);
}
// template <typename T> auto f(T t) { return t; }
// template <typename T> auto f(T* t) { return *t; }
// void g() { int (*p)(int*) = &f; }
public void testAddressOfFunction() throws Exception {
BindingAssertionHelper bh = getAssertionHelper();
ICPPFunctionTemplate f2 = bh.assertNonProblem("f(T*", 1);
ICPPTemplateInstance fi = bh.assertNonProblem("f;", 1);
assertSame(f2, fi.getSpecializedBinding());
}
// struct A { static int i; };
// auto& f1() { return A::i; }
// auto&& f2() { return A::i; }
// auto&& f3() { return 42; }
// const auto& f4() { return A::i; }
// const auto&& f5() { return 42; }
public void testAutoRef() throws Exception {
assertReturnType("f1", CommonCPPTypes.referenceToInt);
assertReturnType("f2", CommonCPPTypes.referenceToInt);
assertReturnType("f3", CommonCPPTypes.rvalueReferenceToInt);
assertReturnType("f4", CommonCPPTypes.referenceToConstInt);
assertReturnType("f5", CommonCPPTypes.rvalueReferenceToConstInt);
}
// struct A { static int i; };
// auto* f1() { return &A::i; }
// const auto* f2() { return &A::i; }
public void testAutoPointer() throws Exception {
assertReturnType("f1", CommonCPPTypes.pointerToInt);
assertReturnType("f2", CommonCPPTypes.pointerToConstInt);
}
// auto f1() {}
// auto& f2() {}
// auto* f3() {}
public void testVoidFunction() throws Exception {
assertReturnType("f1", CommonCPPTypes.void_);
assertReturnTypeProblem("f2");
assertReturnTypeProblem("f3");
}
// struct A { static int i; };
// auto f1() -> auto { return 42; }
// auto f2() -> auto& { return A::i; }
// auto f3() -> auto&& { return A::i; }
// auto f4() -> auto&& { return 42; }
// auto f5() -> const auto& { return A::i; }
// auto f6() -> const auto&& { return 42; }
// auto f7() -> auto* { return &A::i; }
// auto f8() -> const auto* { return &A::i; }
public void testAutoInTrailingReturnType() throws Exception {
assertReturnType("f1", CommonCPPTypes.int_);
assertReturnType("f2", CommonCPPTypes.referenceToInt);
assertReturnType("f3", CommonCPPTypes.referenceToInt);
assertReturnType("f4", CommonCPPTypes.rvalueReferenceToInt);
assertReturnType("f5", CommonCPPTypes.referenceToConstInt);
assertReturnType("f6", CommonCPPTypes.rvalueReferenceToConstInt);
assertReturnType("f7", CommonCPPTypes.pointerToInt);
assertReturnType("f8", CommonCPPTypes.pointerToConstInt);
}
// int i;
// auto f1 = []() -> auto { return 42; };
// auto f2 = []() -> auto& { return i; };
// auto f3 = []() -> auto&& { return i; };
// auto f4 = []() -> auto&& { return 42; };
public void testAutoInLambdaReturnType() throws Exception {
assertLambdaReturnType("f1", CommonCPPTypes.int_);
assertLambdaReturnType("f2", CommonCPPTypes.referenceToInt);
assertLambdaReturnType("f3", CommonCPPTypes.referenceToInt);
assertLambdaReturnType("f4", CommonCPPTypes.rvalueReferenceToInt);
}
// struct A {
// virtual auto f() { return 42; }
// virtual decltype(auto) g() { return 42; }
// };
public void testVirtualAutoFunction() throws Exception {
assertReturnTypeProblem("f");
assertReturnTypeProblem("g");
}
// auto f() { return {1, 2, 3}; }
public void testInitializerList() throws Exception {
assertReturnTypeProblem("f");
}
// int f(int);
// int g(int);
// template <typename T>
// auto foo(bool cond, T arg) {
// if (cond) {
// return f(arg);
// } else {
// return g(arg);
// }
// }
// void bar(bool cond) {
// foo(cond, 0);
// }
public void _testMultipleDependentReturns() throws Exception {
// TODO: To pass this test, we need to defer the checking of whether
// all paths return the same type, until after instantiation.
BindingAssertionHelper bh = getAssertionHelper();
bh.assertNonProblem("foo(cond", "foo");
}
// decltype(auto) f() { return 42; }
// decltype(auto) g(int* arg) { return *arg; }
public void testDecltypeAuto() throws Exception {
assertReturnType("f", CommonCPPTypes.int_);
assertReturnType("g", CommonCPPTypes.referenceToInt);
}
// auto f() -> decltype(auto) { return 42; }
// auto g(int* arg) -> decltype(auto) { return *arg; }
// auto L1 = []() -> decltype(auto) { return 42; };
// auto L2 = [](int* arg) -> decltype(auto) { return *arg; };
public void testDecltypeAutoInTrailingReturnType() throws Exception {
assertReturnType("f", CommonCPPTypes.int_);
assertReturnType("g", CommonCPPTypes.referenceToInt);
assertLambdaReturnType("L1", CommonCPPTypes.int_);
assertLambdaReturnType("L2", CommonCPPTypes.referenceToInt);
}
// int i;
// decltype(auto)& f() { return i; }
// decltype(auto)* g() { return &i; }
// auto f2() -> decltype(auto)& { return i; }
// auto g2() -> decltype(auto)* { return &i; }
public void testDecltypeAutoWithDecoration() throws Exception {
assertReturnTypeProblem("f");
assertReturnTypeProblem("g");
assertReturnTypeProblem("f2");
assertReturnTypeProblem("g2");
}
// auto f();
// auto waldo = f();
public void testUseWithoutDefinition() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableTypeProblem("waldo");
}
// auto f();
// auto f() { return 42; }
// auto waldo = f();
public void testUseAfterDefinition() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableType("waldo", CommonCPPTypes.int_);
}
// auto f();
// auto waldo = f();
// auto f() { return 42; }
public void _testUseBeforeDefinition() throws Exception {
// TODO: To pass this test, we need to apply declaredBefore() filtering
// to the definition search in CPPFunction.getType().
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableTypeProblem("waldo");
}
// auto f() { return 42; }
// int f();
public void testRedeclaration() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
ICPPFunction autoFunction = helper.assertNonProblem("auto f", "f");
// If we start diagnosing invalid redeclarations as errors, it would be
// appropriate to start doing assertProblem() for the "f" in "int f" instead.
ICPPFunction intFunction = helper.assertNonProblem("int f", "f");
assertNotSame(autoFunction, intFunction);
}
// struct A {
// auto f();
// };
// auto A::f() { return 42; }
// auto waldo = A().f();
public void testOutOfLineMethod() throws Exception {
BindingAssertionHelper helper = getAssertionHelper();
helper.assertVariableType("waldo", CommonCPPTypes.int_);
}
}