mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-08-09 17:25:38 +02:00
Bug 408470 - Add partial support for C++14 return type deduction
Out-of-line definitions where the definition is in a different file than the declaration are not supported yet. Change-Id: I3631bdb3e08abe2aab266065c7858c66170fb570
This commit is contained in:
parent
fb847a82ce
commit
619da2a170
35 changed files with 1019 additions and 151 deletions
|
@ -10170,6 +10170,30 @@ public class AST2CPPTests extends AST2TestBase {
|
|||
public void testOverrideSpecifierAfterTrailingReturnType_489876() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// auto (*x1)() -> int;
|
||||
// int (*x2)();
|
||||
//
|
||||
// auto (*y1)() -> int(*)();
|
||||
// int (*(*y2)())();
|
||||
//
|
||||
// auto (*z1)() -> auto(*)() -> int(*)();
|
||||
// int (*(*(*z2)())())();
|
||||
public void testTrailingReturnTypeInFunctionPointer() throws Exception {
|
||||
BindingAssertionHelper bh = getAssertionHelper();
|
||||
|
||||
ICPPVariable x1 = bh.assertNonProblem("x1");
|
||||
ICPPVariable x2 = bh.assertNonProblem("x2");
|
||||
assertSameType(x1.getType(), x2.getType());
|
||||
|
||||
ICPPVariable y1 = bh.assertNonProblem("y1");
|
||||
ICPPVariable y2 = bh.assertNonProblem("y2");
|
||||
assertSameType(y1.getType(), y2.getType());
|
||||
|
||||
ICPPVariable z1 = bh.assertNonProblem("z1");
|
||||
ICPPVariable z2 = bh.assertNonProblem("z2");
|
||||
assertSameType(z1.getType(), z2.getType());
|
||||
}
|
||||
|
||||
// struct CHAINER {
|
||||
// CHAINER const & operator,(int x) const;
|
||||
|
|
|
@ -10306,4 +10306,26 @@ public class AST2TemplateTests extends AST2TestBase {
|
|||
public void testReferenceBinding_Regression_516284() throws Exception {
|
||||
parseAndCheckBindings();
|
||||
}
|
||||
|
||||
// // Declare a constexpr function that turns int and int& into different values.
|
||||
// template <typename T> constexpr int foo();
|
||||
// template <> constexpr int foo<int>() { return 42; };
|
||||
// template <> constexpr int foo<int&>() { return 43; };
|
||||
//
|
||||
// template <typename T>
|
||||
// constexpr int bar(T arg) {
|
||||
// // Bind a TypeOfDependentExpression to an 'auto'.
|
||||
// auto local = *&arg;
|
||||
//
|
||||
// // Leak the deduced type via the return value.
|
||||
// return foo<decltype(local)>();
|
||||
// }
|
||||
//
|
||||
// // Instantiate with [T = int] and capture the return value.
|
||||
// constexpr int waldo = bar(0);
|
||||
public void testDependentTypeBindingToAuto_408470() throws Exception {
|
||||
BindingAssertionHelper helper = getAssertionHelper();
|
||||
// Check that the TypeOfDependentExpression instantiated to the correct type.
|
||||
helper.assertVariableValue("waldo", 42);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.parser.tests.ast2;
|
||||
|
||||
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionTests;
|
||||
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.VariableTemplateTests;
|
||||
import org.eclipse.cdt.core.parser.tests.prefix.CompletionTestSuite;
|
||||
|
||||
|
@ -59,6 +60,7 @@ public class DOMParserTestSuite extends TestCase {
|
|||
suite.addTest(VariableReadWriteFlagsTest.suite());
|
||||
suite.addTest(AST2CPPAttributeTests.suite());
|
||||
suite.addTest(VariableTemplateTests.suite());
|
||||
suite.addTestSuite(ReturnTypeDeductionTests.class);
|
||||
return suite;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.eclipse.cdt.core.dom.ast.IASTNodeSelector;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemType;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
|
||||
|
@ -348,6 +349,11 @@ public class SemanticTestBase extends BaseTestCase {
|
|||
assertSameType(expectedType, var.getType());
|
||||
}
|
||||
|
||||
public void assertVariableTypeProblem(String variableName) {
|
||||
IVariable var = assertNonProblem(variableName);
|
||||
assertInstance(var.getType(), IProblemType.class);
|
||||
}
|
||||
|
||||
public void assertVariableValue(String variableName, long expectedValue) {
|
||||
IVariable var = assertNonProblem(variableName);
|
||||
BaseTestCase.assertVariableValue(var, expectedValue);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*******************************************************************************
|
||||
* 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.internal.index.tests.IndexBindingResolutionTestBase;
|
||||
|
||||
public class ReturnTypeDeductionIndexTests extends IndexBindingResolutionTestBase {
|
||||
public ReturnTypeDeductionIndexTests() {
|
||||
setStrategy(new SinglePDOMTestStrategy(true));
|
||||
}
|
||||
|
||||
// struct A {
|
||||
// auto f();
|
||||
// };
|
||||
// auto A::f() { return 42; }
|
||||
|
||||
// auto waldo = A().f();
|
||||
public void testOutOfLineMethod1() throws Exception {
|
||||
BindingAssertionHelper helper = getAssertionHelper();
|
||||
helper.assertVariableType("waldo", CommonCPPTypes.int_);
|
||||
}
|
||||
|
||||
// struct A {
|
||||
// auto f();
|
||||
// };
|
||||
|
||||
// auto A::f() { return 42; }
|
||||
// auto waldo = A().f();
|
||||
public void _testOutOfLineMethod2() throws Exception {
|
||||
// TODO(nathanridge): Definition is a different file from the declaration is not supported yet.
|
||||
BindingAssertionHelper helper = getAssertionHelper();
|
||||
helper.assertVariableType("waldo", CommonCPPTypes.int_);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
/*******************************************************************************
|
||||
* 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.ParserLanguage;
|
||||
import org.eclipse.cdt.core.parser.tests.ast2.AST2TestBase;
|
||||
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 AST2TestBase {
|
||||
private BindingAssertionHelper getAssertionHelper() throws Exception {
|
||||
return getAssertionHelper(ParserLanguage.CPP);
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
}
|
|
@ -385,6 +385,12 @@ public abstract class IndexBindingResolutionTestBase extends SemanticTestBase {
|
|||
}
|
||||
return i - offset;
|
||||
}
|
||||
|
||||
// Get a BindingAssertionHelper for the last AST.
|
||||
protected BindingAssertionHelper getAssertionHelper() {
|
||||
int index = strategy.getAstCount() - 1;
|
||||
return new BindingAssertionHelper(strategy.getAstSource(index).toString(), strategy.getAst(index));
|
||||
}
|
||||
|
||||
static protected class NameCollector extends ASTVisitor {
|
||||
{
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.index.tests;
|
||||
|
||||
import org.eclipse.cdt.core.parser.tests.ast2.cxx14.ReturnTypeDeductionIndexTests;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
|
@ -35,6 +37,8 @@ public class IndexTests extends TestSuite {
|
|||
suite.addTest(IndexMultiVariantHeaderTest.suite());
|
||||
suite.addTest(IndexMultiFileTest.suite());
|
||||
|
||||
suite.addTestSuite(ReturnTypeDeductionIndexTests.class);
|
||||
|
||||
IndexCPPBindingResolutionBugs.addTests(suite);
|
||||
IndexCPPBindingResolutionTest.addTests(suite);
|
||||
IndexGPPBindingResolutionTest.addTests(suite);
|
||||
|
|
|
@ -45,6 +45,8 @@ public interface ISemanticProblem {
|
|||
int TYPE_ENUMERATION_EXPECTED = 10006;
|
||||
/** @since 6.1 */
|
||||
int TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = 10007;
|
||||
/** @since 6.3 */
|
||||
int TYPE_AUTO_FOR_VIRTUAL_METHOD = 10008;
|
||||
|
||||
/**
|
||||
* Returns the ID of the problem.
|
||||
|
|
|
@ -53,12 +53,23 @@ public interface ICPPFunction extends IFunction, ICPPBinding {
|
|||
public IType[] getExceptionSpecification();
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* Returns the function's type.
|
||||
* Any placeholders in the type are resolved.
|
||||
* If the type contains placeholders and a function definition is not available to
|
||||
* resolve them, a ProblemType is returned (call sites that do not need the
|
||||
* placeholders resolved should call getDeclaredType() instead).
|
||||
* @since 5.1
|
||||
*/
|
||||
@Override
|
||||
public ICPPFunctionType getType();
|
||||
|
||||
/**
|
||||
* Returns the function's declared type.
|
||||
* This is the function's type without any placeholders resolved.
|
||||
* @since 6.3
|
||||
*/
|
||||
public ICPPFunctionType getDeclaredType();
|
||||
|
||||
/**
|
||||
* @since 5.2
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*******************************************************************************
|
||||
* 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.dom.ast.util;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
|
||||
|
||||
/**
|
||||
* An ASTVisitor that visits every return statement in a function
|
||||
* body and calls onReturnStatement() on it.
|
||||
*
|
||||
* @since 6.3
|
||||
*/
|
||||
public abstract class ReturnStatementVisitor extends ASTVisitor {
|
||||
private final IASTFunctionDefinition fFunction;
|
||||
|
||||
/**
|
||||
* Constructs a ReturnStatementVisitor that will visit the
|
||||
* body of a function.
|
||||
* @param function the function to be visited
|
||||
*/
|
||||
protected ReturnStatementVisitor(IASTFunctionDefinition function) {
|
||||
shouldVisitStatements = true;
|
||||
shouldVisitDeclarations = true;
|
||||
shouldVisitExpressions = true;
|
||||
this.fFunction = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the function being visited.
|
||||
*/
|
||||
protected IASTFunctionDefinition getFunction() {
|
||||
return fFunction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a return statement is encountered in the function body.
|
||||
* @param stmt the return statement that was encountered
|
||||
*/
|
||||
protected abstract void onReturnStatement(IASTReturnStatement stmt);
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclaration element) {
|
||||
if (element != fFunction)
|
||||
return PROCESS_SKIP; // skip inner functions
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTExpression expr) {
|
||||
if (expr instanceof ICPPASTLambdaExpression) {
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTStatement stmt) {
|
||||
if (stmt instanceof IASTReturnStatement) {
|
||||
onReturnStatement((IASTReturnStatement) stmt);
|
||||
return PROCESS_SKIP;
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
}
|
|
@ -44,7 +44,8 @@ public interface ITypeMarshalBuffer {
|
|||
UNKNOWN_MEMBER_TYPE = 0x10,
|
||||
INITIALIZER_LIST_TYPE = 0x11,
|
||||
DEFERRED_FUNCTION = 0x12,
|
||||
DEFERRED_VARIABLE_INSTANCE = 0x13;
|
||||
DEFERRED_VARIABLE_INSTANCE = 0x13,
|
||||
PLACEHOLDER_TYPE = 0x14;
|
||||
// Can add more types up to 0x1C, after that it will collide with TypeMarshalBuffer.UNSTORABLE_TYPE.
|
||||
|
||||
final static byte
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.eclipse.core.runtime.CoreException;
|
|||
*/
|
||||
public class ProblemType implements IProblemType, ISerializableType {
|
||||
public static final IType AUTO_FOR_NON_STATIC_FIELD = new ProblemType(TYPE_AUTO_FOR_NON_STATIC_FIELD);
|
||||
public static final IType AUTO_FOR_VIRTUAL_METHOD = new ProblemType(TYPE_AUTO_FOR_VIRTUAL_METHOD);
|
||||
public static final IType CANNOT_DEDUCE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_AUTO_TYPE);
|
||||
public static final IType CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE = new ProblemType(TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE);
|
||||
public static final IType ENUMERATION_EXPECTED = new ProblemType(TYPE_ENUMERATION_EXPECTED);
|
||||
|
|
|
@ -129,6 +129,11 @@ public class CPPClassSpecialization extends CPPSpecialization
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
return new ProblemFunctionType(getID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
return new ProblemFunctionType(getID());
|
||||
|
|
|
@ -22,11 +22,10 @@ import org.eclipse.cdt.core.dom.ILinkage;
|
|||
import org.eclipse.cdt.core.dom.IName;
|
||||
import org.eclipse.cdt.core.dom.ast.EScopeKind;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
|
@ -52,9 +51,9 @@ import org.eclipse.cdt.core.index.IIndexFileSet;
|
|||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||
import org.eclipse.cdt.core.parser.util.IContentAssistMatcher;
|
||||
import org.eclipse.cdt.internal.core.dom.Linkage;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType.PlaceholderKind;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||
import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
|
||||
import org.eclipse.core.runtime.PlatformObject;
|
||||
|
@ -143,33 +142,29 @@ public class CPPClosureType extends PlatformObject implements ICPPClassType, ICP
|
|||
}
|
||||
|
||||
private IType getReturnType() {
|
||||
IASTDeclSpecifier declSpecForDeduction = null;
|
||||
IASTDeclarator declaratorForDeduction = null;
|
||||
ICPPASTFunctionDeclarator lambdaDtor = fLambdaExpression.getDeclarator();
|
||||
PlaceholderKind placeholder = null;
|
||||
if (lambdaDtor != null) {
|
||||
IASTTypeId trailingReturnType = lambdaDtor.getTrailingReturnType();
|
||||
if (trailingReturnType != null) {
|
||||
return CPPVisitor.createType(trailingReturnType);
|
||||
IASTDeclSpecifier declSpec = trailingReturnType.getDeclSpecifier();
|
||||
placeholder = CPPVisitor.usesAuto(declSpec);
|
||||
if (placeholder != null) {
|
||||
declSpecForDeduction = declSpec;
|
||||
declaratorForDeduction = trailingReturnType.getAbstractDeclarator();
|
||||
} else {
|
||||
return CPPVisitor.createType(trailingReturnType);
|
||||
}
|
||||
}
|
||||
}
|
||||
IASTCompoundStatement body = fLambdaExpression.getBody();
|
||||
if (body != null) {
|
||||
IASTStatement[] stmts = body.getStatements();
|
||||
if (stmts.length > 0) {
|
||||
// Gnu extension allows to deduce return type in complex compound statements
|
||||
IASTStatement stmt= stmts[stmts.length - 1];
|
||||
if (stmt instanceof IASTReturnStatement) {
|
||||
IASTReturnStatement rtstmt= (IASTReturnStatement) stmt;
|
||||
IASTExpression expr= rtstmt.getReturnValue();
|
||||
if (expr != null) {
|
||||
IType type= expr.getExpressionType();
|
||||
type= Conversions.lvalue_to_rvalue(type, false);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return CPPVisitor.deduceReturnType(body, declSpecForDeduction, declaratorForDeduction,
|
||||
placeholder, body);
|
||||
}
|
||||
return CPPSemantics.VOID_TYPE;
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
|
||||
private IType[] getParameterTypes() {
|
||||
|
|
|
@ -117,6 +117,11 @@ public class CPPDeferredFunction extends CPPUnknownBinding implements ICPPDeferr
|
|||
return ICPPParameter.EMPTY_CPPPARAMETER_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
return FUNCTION_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
return FUNCTION_TYPE;
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
|
|||
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.ProblemFunctionType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||
import org.eclipse.core.runtime.PlatformObject;
|
||||
|
@ -68,6 +69,7 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt
|
|||
|
||||
protected IASTDeclarator[] declarations;
|
||||
protected ICPPASTFunctionDeclarator definition;
|
||||
protected ICPPFunctionType declaredType;
|
||||
protected ICPPFunctionType type;
|
||||
|
||||
private static final int FULLY_RESOLVED = 1;
|
||||
|
@ -294,23 +296,47 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
// Helper function for getDeclaredType() and getType().
|
||||
public static ICPPFunctionType toFunctionType(IType type) {
|
||||
if (type instanceof ICPPFunctionType) {
|
||||
return (ICPPFunctionType) type;
|
||||
} else {
|
||||
type = getNestedType(type, TDEF);
|
||||
if (type instanceof ICPPFunctionType) {
|
||||
return (ICPPFunctionType) type;
|
||||
} else if (type instanceof ISemanticProblem) {
|
||||
return new ProblemFunctionType(((ISemanticProblem) type).getID());
|
||||
} else {
|
||||
// This case is unexpected
|
||||
return new ProblemFunctionType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
if (declaredType == null) {
|
||||
IType t = CPPVisitor.createType((definition != null) ? definition : declarations[0],
|
||||
CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS);
|
||||
declaredType = toFunctionType(t);
|
||||
}
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
if (type == null) {
|
||||
// TODO: As an optimization, check if declaredType contains placeholders,
|
||||
// and if it doesn't, just return that.
|
||||
IType t = CPPVisitor.createType((definition != null) ? definition : declarations[0]);
|
||||
if (t instanceof ICPPFunctionType) {
|
||||
type = (ICPPFunctionType) t;
|
||||
} else {
|
||||
t = getNestedType(t, TDEF);
|
||||
if (t instanceof ICPPFunctionType) {
|
||||
type = (ICPPFunctionType) t;
|
||||
} else if (t instanceof ISemanticProblem) {
|
||||
type= new ProblemFunctionType(((ISemanticProblem) t).getID());
|
||||
} else {
|
||||
// This case is unexpected
|
||||
type = new ProblemFunctionType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
|
||||
// The declaration may not specify the return type, so look at the definition.
|
||||
if (t == ProblemType.NO_NAME) {
|
||||
findDefinition();
|
||||
if (definition != null) {
|
||||
t = CPPVisitor.createType(definition);
|
||||
}
|
||||
}
|
||||
type = toFunctionType(t);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
@ -713,4 +739,13 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void findDefinition() {
|
||||
if (definition != null)
|
||||
return;
|
||||
|
||||
IASTName[] definitions = declarations[0].getTranslationUnit().getDefinitionsInAST(this);
|
||||
if (definitions.length != 0)
|
||||
addDefinition(definitions[0]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,11 @@ public class CPPFunctionSpecialization extends CPPSpecialization implements ICPP
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
return fType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
return fType;
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.cpp;
|
||||
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.TDEF;
|
||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTTypeUtil;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
||||
|
@ -29,7 +26,6 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
|
|||
import org.eclipse.cdt.core.dom.ast.IFunctionType;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||
import org.eclipse.cdt.core.dom.ast.ISemanticProblem;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
|
||||
|
@ -40,7 +36,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter;
|
|||
import org.eclipse.cdt.core.parser.util.AttributeUtil;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ASTQueries;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ProblemFunctionType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||
|
||||
|
@ -49,6 +44,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
|||
*/
|
||||
public class CPPFunctionTemplate extends CPPTemplateDefinition
|
||||
implements ICPPFunctionTemplate, ICPPInternalFunction {
|
||||
protected ICPPFunctionType declaredType;
|
||||
protected ICPPFunctionType type;
|
||||
|
||||
public CPPFunctionTemplate(IASTName name) {
|
||||
|
@ -169,6 +165,20 @@ public class CPPFunctionTemplate extends CPPTemplateDefinition
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
if (declaredType == null) {
|
||||
IASTName name = getTemplateName();
|
||||
IASTNode parent = name.getParent();
|
||||
while (parent.getParent() instanceof IASTDeclarator)
|
||||
parent = parent.getParent();
|
||||
|
||||
IType t = CPPVisitor.createType((IASTDeclarator) parent, CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS);
|
||||
declaredType = CPPFunction.toFunctionType(t);
|
||||
}
|
||||
return declaredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
if (type == null) {
|
||||
|
@ -176,16 +186,11 @@ public class CPPFunctionTemplate extends CPPTemplateDefinition
|
|||
IASTNode parent = name.getParent();
|
||||
while (parent.getParent() instanceof IASTDeclarator)
|
||||
parent = parent.getParent();
|
||||
|
||||
IType t = getNestedType(CPPVisitor.createType((IASTDeclarator) parent), TDEF);
|
||||
if (t instanceof ICPPFunctionType) {
|
||||
type = (ICPPFunctionType) t;
|
||||
} else if (t instanceof ISemanticProblem) {
|
||||
type= new ProblemFunctionType(((ISemanticProblem) t).getID());
|
||||
} else {
|
||||
// This case is unexpected.
|
||||
type= new ProblemFunctionType(ISemanticProblem.TYPE_UNRESOLVED_NAME);
|
||||
}
|
||||
|
||||
IType t = CPPVisitor.createType((IASTDeclarator) parent);
|
||||
// TODO(nathanridge): Do we need to search for the definition here, if t is
|
||||
// ProblemType.NO_NAME, as in CPPFunction?
|
||||
type = CPPFunction.toFunctionType(t);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,11 @@ public class CPPImplicitFunction extends CPPFunction {
|
|||
public ICPPFunctionType getType() {
|
||||
return functionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
return functionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*******************************************************************************
|
||||
* 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.internal.core.dom.parser.cpp;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ISerializableType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.ITypeMarshalBuffer;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
/**
|
||||
* Represents an occurrence of 'auto' or 'decltype(auto)' that has
|
||||
* not been resolved (replaced with a real type) because the information
|
||||
* necessary to resolve it (the function's body) is not available yet.
|
||||
*/
|
||||
public class CPPPlaceholderType implements ISerializableType, IType {
|
||||
public enum PlaceholderKind {
|
||||
Auto,
|
||||
DecltypeAuto
|
||||
}
|
||||
|
||||
private final PlaceholderKind fPlaceholderKind;
|
||||
|
||||
public CPPPlaceholderType(PlaceholderKind placeholderKind) {
|
||||
fPlaceholderKind = placeholderKind;
|
||||
}
|
||||
|
||||
public PlaceholderKind getPlaceholderKind() {
|
||||
return fPlaceholderKind;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void marshal(ITypeMarshalBuffer buffer) throws CoreException {
|
||||
short firstBytes = ITypeMarshalBuffer.PLACEHOLDER_TYPE;
|
||||
if (fPlaceholderKind == PlaceholderKind.DecltypeAuto) {
|
||||
firstBytes |= ITypeMarshalBuffer.FLAG1;
|
||||
}
|
||||
buffer.putShort(firstBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameType(IType type) {
|
||||
if (type instanceof CPPPlaceholderType) {
|
||||
return fPlaceholderKind == ((CPPPlaceholderType) type).fPlaceholderKind;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
IType t = null;
|
||||
try {
|
||||
t = (IType) super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
// not going to happen
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
public static IType unmarshal(short firstBytes, ITypeMarshalBuffer buffer) {
|
||||
PlaceholderKind kind = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0
|
||||
? PlaceholderKind.DecltypeAuto
|
||||
: PlaceholderKind.Auto;
|
||||
return new CPPPlaceholderType(kind);
|
||||
}
|
||||
}
|
|
@ -65,6 +65,11 @@ public class CPPUnknownMethod extends CPPUnknownMember implements ICPPMethod {
|
|||
return ICPPParameter.EMPTY_CPPPARAMETER_ARRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
return FUNCTION_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
// TODO(nathanridge): We'd like to return a TypeOfUnknownMember here,
|
||||
|
|
|
@ -47,6 +47,11 @@ class AutoTypeResolver implements ICPPFunctionTemplate {
|
|||
return TEMPLATE_PARAMETERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
return functionType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
return functionType;
|
||||
|
|
|
@ -4318,8 +4318,9 @@ public class CPPSemantics {
|
|||
|
||||
declarator= ASTQueries.findTypeRelevantDeclarator(declarator);
|
||||
if (declarator instanceof ICPPASTFunctionDeclarator) {
|
||||
IType type = function.getType();
|
||||
return type.isSameType(CPPVisitor.createType(declarator));
|
||||
// For declaration matching, compare the declared types (placeholders not resolved).
|
||||
IType type = function.getDeclaredType();
|
||||
return type.isSameType(CPPVisitor.createType(declarator, CPPVisitor.DO_NOT_RESOLVE_PLACEHOLDERS));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1523,10 +1523,15 @@ public class CPPTemplates {
|
|||
|
||||
if (type instanceof ICPPUnknownBinding) {
|
||||
if (type instanceof TypeOfDependentExpression) {
|
||||
ICPPEvaluation eval = ((TypeOfDependentExpression) type).getEvaluation();
|
||||
TypeOfDependentExpression dependentType = (TypeOfDependentExpression) type;
|
||||
ICPPEvaluation eval = dependentType.getEvaluation();
|
||||
ICPPEvaluation instantiated = eval.instantiate(context, IntegralValue.MAX_RECURSION_DEPTH);
|
||||
if (instantiated != eval) {
|
||||
return CPPSemantics.getDeclTypeForEvaluation(instantiated, context.getPoint());
|
||||
if (dependentType.isForDecltype()) {
|
||||
return CPPSemantics.getDeclTypeForEvaluation(instantiated, context.getPoint());
|
||||
} else {
|
||||
return instantiated.getType(context.getPoint());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
IBinding binding= resolveUnknown((ICPPUnknownBinding) type, context);
|
||||
|
|
|
@ -72,6 +72,7 @@ import org.eclipse.cdt.core.dom.ast.IASTPointer;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblem;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTProblemHolder;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator;
|
||||
|
@ -170,6 +171,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument;
|
|||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration;
|
||||
import org.eclipse.cdt.core.dom.ast.util.ReturnStatementVisitor;
|
||||
import org.eclipse.cdt.core.index.IIndex;
|
||||
import org.eclipse.cdt.core.index.IIndexBinding;
|
||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||
|
@ -210,6 +212,8 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespace;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPNamespaceAlias;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameter;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType.PlaceholderKind;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType;
|
||||
|
@ -241,6 +245,12 @@ public class CPPVisitor extends ASTQueries {
|
|||
private static final char[][] EMPTY_CHAR_ARRAY_ARRAY = {};
|
||||
public static final IASTInitializerClause[] NO_ARGS = {};
|
||||
|
||||
// Flags for createType().
|
||||
public static final int RESOLVE_PLACEHOLDERS = 0x1;
|
||||
|
||||
// Common combinations of flags.
|
||||
public static final int DO_NOT_RESOLVE_PLACEHOLDERS = 0;
|
||||
|
||||
// Thread-local set of DeclSpecifiers for which auto types are being created.
|
||||
// Used to prevent infinite recursion while processing invalid self-referencing
|
||||
// auto-type declarations.
|
||||
|
@ -1889,7 +1899,7 @@ public class CPPVisitor extends ASTQueries {
|
|||
return pt;
|
||||
}
|
||||
|
||||
private static IType createType(IType returnType, ICPPASTFunctionDeclarator fnDtor) {
|
||||
private static IType createFunctionType(IType returnType, ICPPASTFunctionDeclarator fnDtor) {
|
||||
IType[] pTypes = createParameterTypes(fnDtor);
|
||||
|
||||
IASTName name = fnDtor.getName().getLastName();
|
||||
|
@ -2038,7 +2048,24 @@ public class CPPVisitor extends ASTQueries {
|
|||
return type;
|
||||
}
|
||||
|
||||
public static PlaceholderKind usesAuto(IASTDeclSpecifier declSpec) {
|
||||
if (declSpec instanceof ICPPASTSimpleDeclSpecifier) {
|
||||
int declSpecType = ((ICPPASTSimpleDeclSpecifier) declSpec).getType();
|
||||
if (declSpecType == IASTSimpleDeclSpecifier.t_auto) {
|
||||
return PlaceholderKind.Auto;
|
||||
} else if (declSpecType == IASTSimpleDeclSpecifier.t_decltype_auto) {
|
||||
return PlaceholderKind.DecltypeAuto;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IType createType(IASTDeclarator declarator) {
|
||||
// Resolve placeholders by default.
|
||||
return createType(declarator, RESOLVE_PLACEHOLDERS);
|
||||
}
|
||||
|
||||
public static IType createType(IASTDeclarator declarator, int flags) {
|
||||
if (declarator == null)
|
||||
return ProblemType.NO_NAME;
|
||||
|
||||
|
@ -2061,14 +2088,9 @@ public class CPPVisitor extends ASTQueries {
|
|||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
if (declSpec instanceof ICPPASTSimpleDeclSpecifier) {
|
||||
ICPPASTSimpleDeclSpecifier simpleDeclSpecifier = (ICPPASTSimpleDeclSpecifier) declSpec;
|
||||
int declSpecifierType = simpleDeclSpecifier.getType();
|
||||
if (declSpecifierType == IASTSimpleDeclSpecifier.t_auto) {
|
||||
return createAutoType(declSpec, declarator);
|
||||
} else if (declSpecifierType == IASTSimpleDeclSpecifier.t_decltype_auto) {
|
||||
return createDecltypeAutoType(declarator, simpleDeclSpecifier);
|
||||
}
|
||||
PlaceholderKind placeholder = usesAuto(declSpec);
|
||||
if (placeholder != null) {
|
||||
return createAutoType(declSpec, declarator, flags, placeholder);
|
||||
}
|
||||
|
||||
IType type = createType(declSpec);
|
||||
|
@ -2096,51 +2118,21 @@ public class CPPVisitor extends ASTQueries {
|
|||
return type;
|
||||
}
|
||||
|
||||
private static IType createDecltypeAutoType(IASTDeclarator declarator, ICPPASTSimpleDeclSpecifier simpleDeclSpecifier) {
|
||||
IASTInitializerClause initializerClause = getInitializerClauseForDecltypeAuto(declarator);
|
||||
if (initializerClause instanceof IASTExpression) {
|
||||
return getDeclType((IASTExpression) initializerClause);
|
||||
}
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
|
||||
private static IASTInitializerClause getInitializerClauseForDecltypeAuto(IASTDeclarator declarator) {
|
||||
IASTInitializer initializer = declarator.getInitializer();
|
||||
if (initializer == null) {
|
||||
ICPPASTNewExpression newExpression = findAncestorWithType(declarator, ICPPASTNewExpression.class);
|
||||
if (newExpression != null) {
|
||||
initializer = newExpression.getInitializer();
|
||||
}
|
||||
}
|
||||
if (initializer instanceof IASTEqualsInitializer) {
|
||||
return ((IASTEqualsInitializer) initializer).getInitializerClause();
|
||||
} else if (initializer instanceof ICPPASTConstructorInitializer) {
|
||||
ICPPASTConstructorInitializer constructorInitializer = (ICPPASTConstructorInitializer) initializer;
|
||||
IASTInitializerClause[] arguments = constructorInitializer.getArguments();
|
||||
if (arguments.length == 1) {
|
||||
return arguments[0];
|
||||
}
|
||||
} else if (initializer instanceof IASTInitializerList) {
|
||||
IASTInitializerList initializerList = (IASTInitializerList) initializer;
|
||||
IASTInitializerClause[] clauses = initializerList.getClauses();
|
||||
if (clauses.length == 1) {
|
||||
return clauses[0];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator) {
|
||||
private static IType createAutoType(final IASTDeclSpecifier declSpec, IASTDeclarator declarator,
|
||||
int flags, PlaceholderKind placeholderKind) {
|
||||
IType cannotDeduce = placeholderKind == PlaceholderKind.Auto ?
|
||||
ProblemType.CANNOT_DEDUCE_AUTO_TYPE :
|
||||
ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
Set<IASTDeclSpecifier> recursionProtectionSet = autoTypeDeclSpecs.get();
|
||||
if (!recursionProtectionSet.add(declSpec)) {
|
||||
// Detected a self referring auto type, e.g.: auto x = x;
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
return cannotDeduce;
|
||||
}
|
||||
|
||||
try {
|
||||
if (declarator instanceof ICPPASTFunctionDeclarator) {
|
||||
return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator);
|
||||
return createAutoFunctionType(declSpec, (ICPPASTFunctionDeclarator) declarator, flags,
|
||||
placeholderKind);
|
||||
}
|
||||
ICPPASTInitializerClause autoInitClause= null;
|
||||
IASTNode parent = declarator.getParent().getParent();
|
||||
|
@ -2179,7 +2171,7 @@ public class CPPVisitor extends ASTQueries {
|
|||
beginExpr= new CPPASTFunctionCallExpression(new CPPASTIdExpression(name), beginCallArguments);
|
||||
}
|
||||
} else {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
return cannotDeduce;
|
||||
}
|
||||
}
|
||||
autoInitClause= new CPPASTUnaryExpression(IASTUnaryExpression.op_star, beginExpr);
|
||||
|
@ -2198,74 +2190,239 @@ public class CPPVisitor extends ASTQueries {
|
|||
if (arguments.length == 1)
|
||||
autoInitClause = (ICPPASTInitializerClause) arguments[0];
|
||||
} else if (initClause instanceof ICPPASTInitializerClause) {
|
||||
autoInitClause= (ICPPASTInitializerClause) initClause;
|
||||
if (initClause instanceof ICPPASTInitializerList) {
|
||||
IASTInitializerClause[] clauses = ((ICPPASTInitializerList) initClause).getClauses();
|
||||
if (clauses.length == 1) {
|
||||
autoInitClause = (ICPPASTInitializerClause) clauses[0];
|
||||
}
|
||||
}
|
||||
if (autoInitClause == null) {
|
||||
autoInitClause= (ICPPASTInitializerClause) initClause;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (autoInitClause == null) {
|
||||
return cannotDeduce;
|
||||
}
|
||||
if (placeholderKind == PlaceholderKind.Auto) {
|
||||
return createAutoType(autoInitClause.getEvaluation(), declSpec, declarator, autoInitClause);
|
||||
} else /* decltype(auto) */ {
|
||||
if (declarator.getPointerOperators().length > 0) {
|
||||
// 'decltype(auto)' cannot be combined with * or & the way 'auto' can.
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
if (autoInitClause instanceof IASTExpression) {
|
||||
return getDeclType((IASTExpression) autoInitClause);
|
||||
} else {
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
}
|
||||
return createAutoType(autoInitClause, declSpec, declarator);
|
||||
} finally {
|
||||
recursionProtectionSet.remove(declSpec);
|
||||
}
|
||||
}
|
||||
|
||||
private static IType createAutoType(ICPPASTInitializerClause initClause, IASTDeclSpecifier declSpec,
|
||||
IASTDeclarator declarator) {
|
||||
private static IType createAutoType(final ICPPEvaluation evaluation, IASTDeclSpecifier declSpec,
|
||||
IASTDeclarator declarator, IASTNode point) {
|
||||
// C++0x: 7.1.6.4
|
||||
if (initClause == null) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
|
||||
IType type = AutoTypeResolver.AUTO_TYPE;
|
||||
IType initType = null;
|
||||
ValueCategory valueCat= null;
|
||||
initType = evaluation.getType(declarator);
|
||||
valueCat = evaluation.getValueCategory(declarator);
|
||||
if (initType == null || initType instanceof ISemanticProblem) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
ICPPClassTemplate initializer_list_template = null;
|
||||
if (initClause instanceof ICPPASTInitializerList) {
|
||||
if (evaluation instanceof EvalInitList) {
|
||||
initializer_list_template = get_initializer_list(declSpec);
|
||||
if (initializer_list_template == null) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
type = (IType) CPPTemplates.instantiate(initializer_list_template,
|
||||
new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, initClause);
|
||||
new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, point);
|
||||
if (type instanceof IProblemBinding) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
}
|
||||
type = decorateType(type, declSpec, declarator);
|
||||
final ICPPEvaluation evaluation = initClause.getEvaluation();
|
||||
initType= evaluation.getType(declarator);
|
||||
valueCat= evaluation.getValueCategory(declarator);
|
||||
if (initType == null || initType instanceof ISemanticProblem) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
ICPPFunctionTemplate template = new AutoTypeResolver(type);
|
||||
CPPTemplateParameterMap paramMap = new CPPTemplateParameterMap(1);
|
||||
TemplateArgumentDeduction.deduceFromFunctionArgs(template, Collections.singletonList(initType),
|
||||
Collections.singletonList(valueCat), paramMap, initClause);
|
||||
Collections.singletonList(valueCat), paramMap, point);
|
||||
ICPPTemplateArgument argument = paramMap.getArgument(0, 0);
|
||||
if (argument == null) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
type = argument.getTypeValue();
|
||||
if (type instanceof TypeOfDependentExpression) {
|
||||
// After binding to 'auto', a dependent type no longer acts like 'decltype(expr)'.
|
||||
// For example, after instantiation it's no longer wrapped into a reference type
|
||||
// if it's an lvalue the way 'decltype(expr)' usually is.
|
||||
((TypeOfDependentExpression) type).setIsForDecltype(false);
|
||||
}
|
||||
IType t = SemanticUtil.substituteTypedef(type, initType);
|
||||
if (t != null)
|
||||
type = t;
|
||||
if (initClause instanceof ICPPASTInitializerList) {
|
||||
if (evaluation instanceof EvalInitList) {
|
||||
type = (IType) CPPTemplates.instantiate(initializer_list_template,
|
||||
new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, initClause);
|
||||
new ICPPTemplateArgument[] { new CPPTemplateTypeArgument(type) }, point);
|
||||
}
|
||||
return decorateType(type, declSpec, declarator);
|
||||
}
|
||||
|
||||
private static class ReturnTypeDeducer extends ReturnStatementVisitor {
|
||||
private static final ICPPEvaluation voidEval = new EvalFixed(
|
||||
CPPSemantics.VOID_TYPE, ValueCategory.PRVALUE, IntegralValue.UNKNOWN);
|
||||
|
||||
private ICPPEvaluation fReturnEval = null;
|
||||
private boolean fEncounteredReturnStatement = false;
|
||||
|
||||
protected ReturnTypeDeducer(IASTFunctionDefinition func) {
|
||||
super(func);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onReturnStatement(IASTReturnStatement stmt) {
|
||||
fEncounteredReturnStatement = true;
|
||||
ICPPEvaluation returnEval = null;
|
||||
IASTInitializerClause returnExpression = stmt.getReturnArgument();
|
||||
if (returnExpression == null) {
|
||||
returnEval = voidEval;
|
||||
} else {
|
||||
|
||||
returnEval = ((ICPPASTInitializerClause) returnExpression).getEvaluation();
|
||||
}
|
||||
IType returnType = returnEval.getType(stmt);
|
||||
if (returnType instanceof ISemanticProblem) {
|
||||
// If a function makes a recursive call in some of its return statements,
|
||||
// the type those return expressions will be a problem type. We ignore
|
||||
// these, because we can still successfully deduce from another return
|
||||
// statement that is not recursive.
|
||||
// If all return statements are recursive, fReturnEval will remain null
|
||||
// and getReturnEvaluation() will construct an EvalFixed.INCOMPLETE as desired.
|
||||
return;
|
||||
}
|
||||
|
||||
if (fReturnEval == null) {
|
||||
fReturnEval = returnEval;
|
||||
} else if (!fReturnEval.getType(stmt).isSameType(returnType)) {
|
||||
fReturnEval = EvalFixed.INCOMPLETE;
|
||||
}
|
||||
}
|
||||
|
||||
public ICPPEvaluation getReturnEvaluation() {
|
||||
if (fReturnEval == null) {
|
||||
if (!fEncounteredReturnStatement) {
|
||||
return voidEval;
|
||||
}
|
||||
fReturnEval = EvalFixed.INCOMPLETE;
|
||||
}
|
||||
return fReturnEval;
|
||||
}
|
||||
}
|
||||
|
||||
public static IType deduceReturnType(IASTStatement functionBody, IASTDeclSpecifier autoDeclSpec,
|
||||
IASTDeclarator autoDeclarator, PlaceholderKind placeholder, IASTNode point) {
|
||||
ICPPEvaluation returnEval = null;
|
||||
if (functionBody != null) {
|
||||
ReturnTypeDeducer deducer = new ReturnTypeDeducer(null);
|
||||
functionBody.accept(deducer);
|
||||
returnEval = deducer.getReturnEvaluation();
|
||||
}
|
||||
if (returnEval == null || returnEval == EvalFixed.INCOMPLETE) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
|
||||
// [dcl.spec.auto] p7:
|
||||
// If the deduction is for a return statement and the initializer is a
|
||||
// braced-init-list, the proram is ill-formed.
|
||||
if (returnEval instanceof EvalInitList) {
|
||||
return ProblemType.CANNOT_DEDUCE_AUTO_TYPE;
|
||||
}
|
||||
|
||||
if (placeholder == PlaceholderKind.DecltypeAuto) {
|
||||
if (autoDeclarator != null && autoDeclarator.getPointerOperators().length > 0) {
|
||||
// 'decltype(auto)' cannot be combined with * or & the way 'auto' can.
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
return CPPSemantics.getDeclTypeForEvaluation(returnEval, point);
|
||||
} else /* auto */ {
|
||||
if (autoDeclSpec == null || autoDeclarator == null) {
|
||||
return returnEval.getType(point);
|
||||
} else {
|
||||
return createAutoType(returnEval, autoDeclSpec, autoDeclarator, autoDeclarator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* C++0x: [8.3.5-2]
|
||||
*/
|
||||
private static IType createAutoFunctionType(IASTDeclSpecifier declSpec, ICPPASTFunctionDeclarator declarator) {
|
||||
IASTTypeId id= declarator.getTrailingReturnType();
|
||||
if (id == null)
|
||||
return ProblemType.NO_NAME;
|
||||
|
||||
IType t= createType(id.getAbstractDeclarator());
|
||||
t= qualifyType(t, declSpec);
|
||||
return createType(t, declarator);
|
||||
private static IType createAutoFunctionType(IASTDeclSpecifier declSpec,
|
||||
ICPPASTFunctionDeclarator declarator, int flags, PlaceholderKind placeholder) {
|
||||
IType returnType = null;
|
||||
IASTDeclSpecifier declSpecForDeduction = null;
|
||||
IASTDeclarator declaratorForDeduction = null;
|
||||
IASTTypeId trailingReturnType = declarator.getTrailingReturnType();
|
||||
if (trailingReturnType == null) {
|
||||
// No trailing return type.
|
||||
if ((flags & RESOLVE_PLACEHOLDERS) != 0) {
|
||||
declSpecForDeduction = declSpec;
|
||||
declaratorForDeduction = declarator;
|
||||
} else {
|
||||
returnType = new CPPPlaceholderType(PlaceholderKind.Auto);
|
||||
}
|
||||
} else {
|
||||
IASTDeclSpecifier trailingDeclSpec = trailingReturnType.getDeclSpecifier();
|
||||
IASTDeclarator trailingDeclarator = trailingReturnType.getAbstractDeclarator();
|
||||
PlaceholderKind trailingPlaceholder = usesAuto(trailingDeclSpec);
|
||||
if (trailingPlaceholder != null && !(trailingDeclarator instanceof IASTFunctionDeclarator)) {
|
||||
// Trailing return type uses 'auto', other than to introduce
|
||||
// another trailing return type for a function type, so we'll
|
||||
// need to look at the function body and deduce the return type.
|
||||
declSpecForDeduction = trailingDeclSpec;
|
||||
declaratorForDeduction = trailingDeclarator;
|
||||
placeholder = trailingPlaceholder;
|
||||
} else {
|
||||
// Trailing return type specifies the type.
|
||||
returnType = createType(trailingDeclarator);
|
||||
returnType = qualifyType(returnType, declSpec);
|
||||
}
|
||||
}
|
||||
|
||||
if (returnType == null) {
|
||||
// Try to deduce return type from return statement.
|
||||
|
||||
// [dcl.spec.auto] p14:
|
||||
// A function declared with a return type that uses a placeholder type
|
||||
// shall not be virtual.
|
||||
if (((ICPPASTDeclSpecifier) declSpec).isVirtual())
|
||||
return ProblemType.AUTO_FOR_VIRTUAL_METHOD;
|
||||
|
||||
ICPPASTFunctionDefinition definition= CPPFunction.getFunctionDefinition(declarator);
|
||||
if (definition != null) {
|
||||
returnType = deduceReturnType(definition.getBody(), declSpecForDeduction,
|
||||
declaratorForDeduction, placeholder, declaratorForDeduction);
|
||||
}
|
||||
}
|
||||
|
||||
if (returnType != null) {
|
||||
// Do not use createFunctionType() because that would decorate the return type
|
||||
// with pointer operators from e.g. an 'auto &', but we have already done that
|
||||
// above.
|
||||
IType[] pTypes = createParameterTypes(declarator);
|
||||
RefQualifier refQualifier = declarator.getRefQualifier();
|
||||
IType result = new CPPFunctionType(returnType, pTypes, declarator.isConst(), declarator.isVolatile(),
|
||||
refQualifier != null, refQualifier == RefQualifier.RVALUE, declarator.takesVarArgs());
|
||||
final IASTDeclarator nested = declarator.getNestedDeclarator();
|
||||
if (nested != null) {
|
||||
result = createType(result, nested);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return ProblemType.NO_NAME;
|
||||
|
||||
}
|
||||
|
||||
public static IType createType(IASTDeclSpecifier declSpec) {
|
||||
|
@ -2310,10 +2467,12 @@ public class CPPVisitor extends ASTQueries {
|
|||
return ProblemType.UNRESOLVED_NAME;
|
||||
}
|
||||
|
||||
// Helper function for createAutoType().
|
||||
private static IType decorateType(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) {
|
||||
type = qualifyType(type, declSpec);
|
||||
type = makeConstIfConstexpr(type, declSpec, declarator);
|
||||
return createType(type, declarator);
|
||||
// Ignore function declarator because we already handled that in createAutoFunctionType().
|
||||
return createType(type, declarator, true /* ignore function declarator */);
|
||||
}
|
||||
|
||||
private static IType makeConstIfConstexpr(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) {
|
||||
|
@ -2333,8 +2492,12 @@ public class CPPVisitor extends ASTQueries {
|
|||
}
|
||||
|
||||
private static IType createType(IType baseType, IASTDeclarator declarator) {
|
||||
if (declarator instanceof ICPPASTFunctionDeclarator)
|
||||
return createType(baseType, (ICPPASTFunctionDeclarator) declarator);
|
||||
return createType(baseType, declarator, false);
|
||||
}
|
||||
|
||||
private static IType createType(IType baseType, IASTDeclarator declarator, boolean ignoreFunctionDeclarator) {
|
||||
if (!ignoreFunctionDeclarator && declarator instanceof ICPPASTFunctionDeclarator)
|
||||
return createFunctionType(baseType, (ICPPASTFunctionDeclarator) declarator);
|
||||
|
||||
IType type = baseType;
|
||||
type = applyAttributes(type, declarator);
|
||||
|
|
|
@ -251,6 +251,10 @@ public class TemplateArgumentDeduction {
|
|||
TemplateArgumentDeduction deduct, IASTNode point) throws DOMException {
|
||||
boolean isReferenceTypeParameter= false;
|
||||
if (par instanceof ICPPReferenceType) {
|
||||
// Cannot deduce a reference type from a void type.
|
||||
if (SemanticUtil.isVoidType(arg)) {
|
||||
return false;
|
||||
}
|
||||
// If P is an rvalue reference to a cv-unqualified template parameter and the argument
|
||||
// is an lvalue, the type "lvalue reference to A" is used in place of A for type
|
||||
// deduction.
|
||||
|
|
|
@ -27,15 +27,30 @@ import org.eclipse.core.runtime.CoreException;
|
|||
*/
|
||||
public class TypeOfDependentExpression extends CPPUnknownBinding implements ICPPUnknownType, ISerializableType {
|
||||
private final ICPPEvaluation fEvaluation;
|
||||
// Whether this represents a decltype(expr), or a dependent type in another context.
|
||||
private boolean fIsForDecltype;
|
||||
|
||||
public TypeOfDependentExpression(ICPPEvaluation evaluation) {
|
||||
super(null);
|
||||
fEvaluation= evaluation;
|
||||
this(evaluation, true);
|
||||
}
|
||||
|
||||
|
||||
public TypeOfDependentExpression(ICPPEvaluation evaluation, boolean isForDecltype) {
|
||||
super(null);
|
||||
fEvaluation = evaluation;
|
||||
fIsForDecltype = isForDecltype;
|
||||
}
|
||||
|
||||
public ICPPEvaluation getEvaluation() {
|
||||
return fEvaluation;
|
||||
}
|
||||
|
||||
public boolean isForDecltype() {
|
||||
return fIsForDecltype;
|
||||
}
|
||||
|
||||
public void setIsForDecltype(boolean isForDecltype) {
|
||||
fIsForDecltype = isForDecltype;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSameType(IType type) {
|
||||
|
@ -61,14 +76,20 @@ public class TypeOfDependentExpression extends CPPUnknownBinding implements ICPP
|
|||
|
||||
@Override
|
||||
public void marshal(ITypeMarshalBuffer buffer) throws CoreException {
|
||||
buffer.putShort(ITypeMarshalBuffer.DEPENDENT_EXPRESSION_TYPE);
|
||||
short firstBytes = ITypeMarshalBuffer.DEPENDENT_EXPRESSION_TYPE;
|
||||
if (fIsForDecltype) {
|
||||
firstBytes |= ITypeMarshalBuffer.FLAG1;
|
||||
}
|
||||
buffer.putShort(firstBytes);
|
||||
buffer.marshalEvaluation(fEvaluation, false);
|
||||
}
|
||||
|
||||
public static IType unmarshal(short firstBytes, ITypeMarshalBuffer buffer) throws CoreException {
|
||||
ICPPEvaluation eval= buffer.unmarshalEvaluation();
|
||||
if (eval != null)
|
||||
return new TypeOfDependentExpression(eval);
|
||||
if (eval != null) {
|
||||
boolean isForDecltype = (firstBytes & ITypeMarshalBuffer.FLAG1) != 0;
|
||||
return new TypeOfDependentExpression(eval, isForDecltype);
|
||||
}
|
||||
return ProblemType.UNKNOWN_FOR_EXPRESSION;
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,12 @@ class CompositeCPPFunction extends CompositeCPPBinding implements ICPPFunction,
|
|||
IType rtype = ((ICPPFunction) rbinding).getType();
|
||||
return (ICPPFunctionType) cf.getCompositeType(rtype);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
IType rtype = ((ICPPFunction) rbinding).getDeclaredType();
|
||||
return (ICPPFunctionType) cf.getCompositeType(rtype);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeleted() {
|
||||
|
|
|
@ -101,6 +101,7 @@ public class ParserMessages {
|
|||
case ISemanticProblem.TYPE_NOT_PERSISTED: return "ISemanticProblem.TYPE_NOT_PERSISTED";
|
||||
case ISemanticProblem.TYPE_ENUMERATION_EXPECTED: return "ISemanticProblem.TYPE_ENUMERATION_EXPECTED";
|
||||
case ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE: return "ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE";
|
||||
case ISemanticProblem.TYPE_AUTO_FOR_VIRTUAL_METHOD: return "ISemanticProblem.TYPE_AUTO_FOR_VIRTUAL_METHOD";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -75,3 +75,4 @@ ISemanticProblem.TYPE_UNKNOWN_FOR_EXPRESSION=Failure to determine type of expres
|
|||
ISemanticProblem.TYPE_NOT_PERSISTED=Failure to store type in the index
|
||||
ISemanticProblem.TYPE_ENUMERATION_EXPECTED=Enumeration expected
|
||||
ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE=Failure to determine decltype(auto)-type
|
||||
ISemanticProblem.TYPE_AUTO_FOR_VIRTUAL_METHOD=Illegally auto-typed virtual method
|
|
@ -285,10 +285,11 @@ public class PDOM extends PlatformObject implements IPDOM {
|
|||
* 207.0 - Store a caller record for macro reference names.
|
||||
* 208.0 - Trigger index rebuild to rebuild corrupted binding reference lists, bug 399147.
|
||||
* 209.0 - Alias templates and their instances take up more space than required, bug 516385.
|
||||
* 210.0 - Return type deduction, bug 408470.
|
||||
*/
|
||||
private static final int MIN_SUPPORTED_VERSION= version(209, 0);
|
||||
private static final int MAX_SUPPORTED_VERSION= version(209, Short.MAX_VALUE);
|
||||
private static final int DEFAULT_VERSION = version(209, 0);
|
||||
private static final int MIN_SUPPORTED_VERSION= version(210, 0);
|
||||
private static final int MAX_SUPPORTED_VERSION= version(210, Short.MAX_VALUE);
|
||||
private static final int DEFAULT_VERSION = version(210, 0);
|
||||
|
||||
private static int version(int major, int minor) {
|
||||
return (major << 16) + minor;
|
||||
|
|
|
@ -78,15 +78,19 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl
|
|||
/** Offset of the function body execution for constexpr functions. */
|
||||
private static final int FUNCTION_BODY = REQUIRED_ARG_COUNT + 2; // Database.EXECUTION_SIZE
|
||||
|
||||
/** Offset of the function's declared type. */
|
||||
private static final int DECLARED_TYPE = FUNCTION_BODY + Database.EXECUTION_SIZE; // Database.TYPE_SIZE
|
||||
|
||||
/**
|
||||
* The size in bytes of a PDOMCPPFunction record in the database.
|
||||
*/
|
||||
@SuppressWarnings("hiding")
|
||||
protected static final int RECORD_SIZE = FUNCTION_BODY + Database.EXECUTION_SIZE;
|
||||
protected static final int RECORD_SIZE = DECLARED_TYPE + Database.TYPE_SIZE;
|
||||
|
||||
private short fAnnotations = -1;
|
||||
private int fRequiredArgCount = -1;
|
||||
private ICPPFunctionType fType; // No need for volatile, all fields of ICPPFunctionTypes are final.
|
||||
private ICPPFunctionType fDeclaredType;
|
||||
|
||||
public PDOMCPPFunction(PDOMCPPLinkage linkage, PDOMNode parent, ICPPFunction function,
|
||||
boolean setTypes, IASTNode point) throws CoreException, DOMException {
|
||||
|
@ -105,10 +109,11 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl
|
|||
return PDOMCPPAnnotations.encodeFunctionAnnotations(function);
|
||||
}
|
||||
|
||||
public void initData(ICPPFunctionType ftype, ICPPParameter[] params, IType[] exceptionSpec,
|
||||
ICPPExecution functionBody) {
|
||||
public void initData(ICPPFunctionType ftype, ICPPFunctionType declaredType, ICPPParameter[] params,
|
||||
IType[] exceptionSpec, ICPPExecution functionBody) {
|
||||
try {
|
||||
setType(ftype);
|
||||
setDeclaredType(declaredType);
|
||||
setParameters(params);
|
||||
storeExceptionSpec(exceptionSpec);
|
||||
getLinkage().storeExecution(record + FUNCTION_BODY, functionBody);
|
||||
|
@ -124,16 +129,20 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl
|
|||
|
||||
ICPPFunction func = (ICPPFunction) newBinding;
|
||||
ICPPFunctionType newType;
|
||||
ICPPFunctionType newDeclaredType;
|
||||
ICPPParameter[] newParams;
|
||||
short newAnnotation;
|
||||
int newBindingRequiredArgCount;
|
||||
newType = func.getType();
|
||||
newDeclaredType = func.getDeclaredType();
|
||||
newParams = func.getParameters();
|
||||
newAnnotation = getAnnotations(func);
|
||||
newBindingRequiredArgCount = func.getRequiredArgumentCount();
|
||||
|
||||
fType = null;
|
||||
fDeclaredType = null;
|
||||
linkage.storeType(record + FUNCTION_TYPE, newType);
|
||||
linkage.storeType(record + DECLARED_TYPE, newDeclaredType);
|
||||
|
||||
PDOMCPPParameter oldParams = getFirstParameter(null);
|
||||
int requiredCount;
|
||||
|
@ -206,6 +215,11 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl
|
|||
fType = null;
|
||||
getLinkage().storeType(record + FUNCTION_TYPE, ft);
|
||||
}
|
||||
|
||||
private void setDeclaredType(ICPPFunctionType ft) throws CoreException {
|
||||
fType = null;
|
||||
getLinkage().storeType(record + DECLARED_TYPE, ft);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSignatureHash() throws CoreException {
|
||||
|
@ -303,6 +317,19 @@ class PDOMCPPFunction extends PDOMCPPBinding implements ICPPFunction, IPDOMOverl
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
if (fDeclaredType == null) {
|
||||
try {
|
||||
fDeclaredType = (ICPPFunctionType) getLinkage().loadType(record + DECLARED_TYPE);
|
||||
} catch (CoreException e) {
|
||||
CCorePlugin.log(e);
|
||||
fDeclaredType = new ProblemFunctionType(ISemanticProblem.TYPE_NOT_PERSISTED);
|
||||
}
|
||||
}
|
||||
return fDeclaredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ICPPFunctionType getType() {
|
||||
if (fType == null) {
|
||||
|
|
|
@ -61,14 +61,18 @@ class PDOMCPPFunctionSpecialization extends PDOMCPPSpecialization
|
|||
|
||||
/** Offset of the function body execution for constexpr functions. */
|
||||
private static final int FUNCTION_BODY = REQUIRED_ARG_COUNT + 2; // Database.EXECUTION_SIZE
|
||||
|
||||
/** Offset of the function's declared type. */
|
||||
private static final int DECLARED_TYPE = FUNCTION_BODY + Database.EXECUTION_SIZE; // Database.TYPE_SIZE
|
||||
|
||||
/**
|
||||
* The size in bytes of a PDOMCPPFunctionSpecialization record in the database.
|
||||
*/
|
||||
@SuppressWarnings("hiding")
|
||||
protected static final int RECORD_SIZE = FUNCTION_BODY + Database.EXECUTION_SIZE;
|
||||
protected static final int RECORD_SIZE = DECLARED_TYPE + Database.TYPE_SIZE;
|
||||
|
||||
private ICPPFunctionType fType; // No need for volatile, all fields of ICPPFunctionTypes are final.
|
||||
private ICPPFunctionType fDeclaredType;
|
||||
private short fAnnotations= -1;
|
||||
private int fRequiredArgCount= -1;
|
||||
|
||||
|
@ -82,6 +86,10 @@ class PDOMCPPFunctionSpecialization extends PDOMCPPSpecialization
|
|||
if (astFt != null) {
|
||||
getLinkage().storeType(record + FUNCTION_TYPE, astFt);
|
||||
}
|
||||
IFunctionType astDeclaredType = astFunction.getDeclaredType();
|
||||
if (astDeclaredType != null) {
|
||||
getLinkage().storeType(record + DECLARED_TYPE, astDeclaredType);
|
||||
}
|
||||
|
||||
ICPPFunction origAstFunc= (ICPPFunction) ((ICPPSpecialization) astFunction).getSpecializedBinding();
|
||||
ICPPParameter[] origAstParams= origAstFunc.getParameters();
|
||||
|
@ -201,6 +209,19 @@ class PDOMCPPFunctionSpecialization extends PDOMCPPSpecialization
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getDeclaredType() {
|
||||
if (fDeclaredType == null) {
|
||||
try {
|
||||
fDeclaredType = (ICPPFunctionType) getLinkage().loadType(record + DECLARED_TYPE);
|
||||
} catch (CoreException e) {
|
||||
CCorePlugin.log(e);
|
||||
fDeclaredType = new ProblemFunctionType(ISemanticProblem.TYPE_NOT_PERSISTED);
|
||||
}
|
||||
}
|
||||
return fDeclaredType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICPPFunctionType getType() {
|
||||
if (fType == null) {
|
||||
|
|
|
@ -100,6 +100,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction;
|
|||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunctionType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPImplicitMethod;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPParameterPackType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPlaceholderType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerToMemberType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPPointerType;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPQualifierType;
|
||||
|
@ -291,6 +292,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
class ConfigureFunction implements Runnable {
|
||||
private final PDOMCPPFunction fFunction;
|
||||
private final ICPPFunctionType fOriginalFunctionType;
|
||||
private final ICPPFunctionType fDeclaredType;
|
||||
private final ICPPParameter[] fOriginalParameters;
|
||||
private final IType[] fOriginalExceptionSpec;
|
||||
private final ICPPExecution fFunctionBody;
|
||||
|
@ -299,6 +301,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
throws DOMException {
|
||||
fFunction = function;
|
||||
fOriginalFunctionType= original.getType();
|
||||
fDeclaredType = original.getDeclaredType();
|
||||
fOriginalParameters= original.getParameters();
|
||||
fOriginalExceptionSpec= function.extractExceptionSpec(original);
|
||||
fFunctionBody = CPPFunction.getFunctionBodyExecution(original, point);
|
||||
|
@ -307,8 +310,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
|
||||
@Override
|
||||
public void run() {
|
||||
fFunction.initData(fOriginalFunctionType, fOriginalParameters, fOriginalExceptionSpec,
|
||||
fFunctionBody);
|
||||
fFunction.initData(fOriginalFunctionType, fDeclaredType, fOriginalParameters,
|
||||
fOriginalExceptionSpec, fFunctionBody);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -399,6 +402,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
private final IPDOMCPPTemplateParameter[] fTemplateParameters;
|
||||
private final ICPPTemplateParameter[] fOriginalTemplateParameters;
|
||||
private final ICPPFunctionType fOriginalFunctionType;
|
||||
private final ICPPFunctionType fDeclaredType;
|
||||
private final ICPPParameter[] fOriginalParameters;
|
||||
private final IType[] fOriginalExceptionSpec;
|
||||
private final ICPPExecution fFunctionBody;
|
||||
|
@ -409,6 +413,7 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
fTemplateParameters= template.getTemplateParameters();
|
||||
fOriginalTemplateParameters= original.getTemplateParameters();
|
||||
fOriginalFunctionType= original.getType();
|
||||
fDeclaredType = original.getDeclaredType();
|
||||
fOriginalParameters= original.getParameters();
|
||||
fOriginalExceptionSpec= template.extractExceptionSpec(original);
|
||||
fFunctionBody = CPPFunction.getFunctionBodyExecution(original, point);
|
||||
|
@ -422,8 +427,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
if (tp != null)
|
||||
tp.configure(fOriginalTemplateParameters[i]);
|
||||
}
|
||||
fTemplate.initData(fOriginalFunctionType, fOriginalParameters, fOriginalExceptionSpec,
|
||||
fFunctionBody);
|
||||
fTemplate.initData(fOriginalFunctionType, fDeclaredType, fOriginalParameters,
|
||||
fOriginalExceptionSpec, fFunctionBody);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1542,6 +1547,8 @@ class PDOMCPPLinkage extends PDOMLinkage implements IIndexCPPBindingConstants {
|
|||
return TypeOfUnknownMember.unmarshal(getPDOM(), firstBytes, buffer);
|
||||
case ITypeMarshalBuffer.INITIALIZER_LIST_TYPE:
|
||||
return InitializerListType.unmarshal(firstBytes, buffer);
|
||||
case ITypeMarshalBuffer.PLACEHOLDER_TYPE:
|
||||
return CPPPlaceholderType.unmarshal(firstBytes, buffer);
|
||||
// Don't handle DEFERRED_FUNCTION, because it's never a type.
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue