Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Ridge2018-10-15 02:01:01 -0400
committerNathan Ridge2018-10-28 22:52:37 -0400
commita00346af224c6a60a70151908790272d54d58955 (patch)
tree8f8a27490fdeb86728661972cebfc278524b53d0
parent4689fdee6829bca2938e7f9cb4e9df97b9d264e3 (diff)
downloadorg.eclipse.cdt-a00346af224c6a60a70151908790272d54d58955.tar.gz
org.eclipse.cdt-a00346af224c6a60a70151908790272d54d58955.tar.xz
org.eclipse.cdt-a00346af224c6a60a70151908790272d54d58955.zip
Bug 540112 - Perform C++14 return type deduction in ReturnChecker
As part of this change, ReturnChecker was refactored to compute the return type as an IType, which allowed for removal of some logic in ReturnChecker which duplicated CPPVisitor's type resolution work. Change-Id: I9cd8512164d650a5ee11d2e58fdae477e3c428a2
-rw-r--r--codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ReturnChecker.java86
-rw-r--r--codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/CxxAstUtils.java15
-rw-r--r--codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java5
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java19
-rw-r--r--core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java20
5 files changed, 65 insertions, 80 deletions
diff --git a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ReturnChecker.java b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ReturnChecker.java
index 8b23febac1..a2b3389233 100644
--- a/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ReturnChecker.java
+++ b/codan/org.eclipse.cdt.codan.checkers/src/org/eclipse/cdt/codan/internal/checkers/ReturnChecker.java
@@ -25,33 +25,26 @@ import org.eclipse.cdt.codan.core.model.cfg.IControlFlowGraph;
import org.eclipse.cdt.codan.core.model.cfg.IExitNode;
import org.eclipse.cdt.codan.internal.core.cfg.ControlFlowGraph;
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
-import org.eclipse.cdt.core.dom.ast.DOMException;
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
-import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTDoStatement;
import org.eclipse.cdt.core.dom.ast.IASTExpression;
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
-import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
-import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTStatement;
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
-import org.eclipse.cdt.core.dom.ast.IASTTypeId;
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
import org.eclipse.cdt.core.dom.ast.IBasicType;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IType;
-import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLambdaExpression;
-import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
@@ -70,6 +63,8 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
public static final String RET_NO_VALUE_ID = "org.eclipse.cdt.codan.checkers.noreturn"; //$NON-NLS-1$
public static final String RET_ERR_VALUE_ID = "org.eclipse.cdt.codan.checkers.errreturnvalue"; //$NON-NLS-1$
public static final String RET_NORET_ID = "org.eclipse.cdt.codan.checkers.errnoreturn"; //$NON-NLS-1$
+
+ private IType cachedReturnType = null;
class ReturnStmpVisitor extends ASTVisitor {
private final IASTFunctionDefinition func;
@@ -149,6 +144,7 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
@Override
protected void processFunction(IASTFunctionDefinition func) {
+ cachedReturnType = null;
if (func.getParent() instanceof ICPPASTTemplateDeclaration)
return; // If it is template get out of here.
ReturnStmpVisitor visitor = new ReturnStmpVisitor(func);
@@ -190,6 +186,8 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
return false;
}
+ @SuppressWarnings("restriction")
+ // TODO: Any reason not to just expose getDeadNodes() in IControlFlowGraph?
public Collection<IBasicBlock> getDeadBlocks(IASTFunctionDefinition func) {
IControlFlowGraph graph = getModelCache().getControlFlowGraph(func);
return ((ControlFlowGraph) graph).getDeadNodes();
@@ -245,7 +243,9 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
}
protected boolean isExplicitReturn(IASTFunctionDefinition func) {
- return getDeclSpecType(func) != IASTSimpleDeclSpecifier.t_unspecified;
+ IASTDeclSpecifier declSpecifier = func.getDeclSpecifier();
+ return !(declSpecifier instanceof IASTSimpleDeclSpecifier &&
+ ((IASTSimpleDeclSpecifier) declSpecifier).getType() == IASTSimpleDeclSpecifier.t_unspecified);
}
/**
@@ -258,41 +258,21 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
private boolean isNonVoid(IASTFunctionDefinition func) {
if (isConstructorDestructor(func))
return false;
- int type = getDeclSpecType(func);
- if (type == IASTSimpleDeclSpecifier.t_void) {
- IASTFunctionDeclarator declarator = func.getDeclarator();
- if (declarator.getPointerOperators().length == 0)
- return false;
- } else if (type == IASTSimpleDeclSpecifier.t_auto && isAutoVoid(func)) {
- return false;
+ return !isVoid(getReturnType(func));
+ }
+
+
+ private IType getReturnType(IASTFunctionDefinition func) {
+ if (cachedReturnType == null) {
+ cachedReturnType = CxxAstUtils.getReturnType(func);
}
- return true;
+ return cachedReturnType;
}
- /**
- * Checks if type if void.
- *
- * @param type
- * @throws DOMException
- */
public boolean isVoid(IType type) {
return type instanceof IBasicType && ((IBasicType) type).getKind() == IBasicType.Kind.eVoid;
}
- protected int getDeclSpecType(IASTFunctionDefinition func) {
- IASTDeclSpecifier declSpecifier = func.getDeclSpecifier();
- int type = -1;
- if (declSpecifier instanceof IASTSimpleDeclSpecifier) {
- type = ((IASTSimpleDeclSpecifier) declSpecifier).getType();
- } else if (declSpecifier instanceof IASTNamedTypeSpecifier) {
- IBinding binding = ((IASTNamedTypeSpecifier) declSpecifier).getName().resolveBinding();
- IType utype = CxxAstUtils.unwindTypedef((IType) binding);
- if (isVoid(utype))
- return IASTSimpleDeclSpecifier.t_void;
- }
- return type;
- }
-
@Override
public void initPreferences(IProblemWorkingCopy problem) {
super.initPreferences(problem);
@@ -300,38 +280,4 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
addPreference(problem, PARAM_IMPLICIT, CheckersMessages.ReturnChecker_Param0, Boolean.FALSE);
}
}
-
- /**
- * Checks if a {@code void} return type is specified using the C++11 late-specified return type
- * for a given function definition.
- * <p>
- * For example, <code>auto f() -> void {}</code> would return {@code true}.
- *
- * @param functionDefinition
- * @return {@code true} if the function has a void (late-specified) return type,
- * {@code false} otherwise
- */
- private boolean isAutoVoid(IASTFunctionDefinition functionDefinition) {
- IASTFunctionDeclarator declarator = functionDefinition.getDeclarator();
- if (declarator instanceof ICPPASTFunctionDeclarator) {
- ICPPASTFunctionDeclarator functionDeclarator = (ICPPASTFunctionDeclarator) declarator;
- IASTTypeId trailingReturnType = functionDeclarator.getTrailingReturnType();
- if (trailingReturnType != null) {
- IASTDeclarator abstractDeclarator = trailingReturnType.getAbstractDeclarator();
- if (abstractDeclarator != null) {
- if (abstractDeclarator.getPointerOperators().length != 0) {
- return false;
- }
- IASTDeclSpecifier declSpecifier = trailingReturnType.getDeclSpecifier();
- if (declSpecifier instanceof ICPPASTSimpleDeclSpecifier) {
- ICPPASTSimpleDeclSpecifier simpleDeclSpecifier = (ICPPASTSimpleDeclSpecifier) declSpecifier;
- if (simpleDeclSpecifier.getType() == IASTSimpleDeclSpecifier.t_void) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
}
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/CxxAstUtils.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/CxxAstUtils.java
index ff9f109611..7f992fc885 100644
--- a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/CxxAstUtils.java
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/CxxAstUtils.java
@@ -50,6 +50,7 @@ import org.eclipse.cdt.core.dom.ast.IFunction;
import org.eclipse.cdt.core.dom.ast.INodeFactory;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.IType;
+import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.rewrite.DeclarationGenerator;
import org.eclipse.cdt.core.index.IIndex;
@@ -57,6 +58,8 @@ import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexName;
import org.eclipse.cdt.core.model.CoreModelUtil;
import org.eclipse.cdt.core.model.ITranslationUnit;
+import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor;
+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.CoreException;
@@ -422,4 +425,16 @@ public final class CxxAstUtils {
}
return functionNameExpression.getRawSignature().equals("exit"); //$NON-NLS-1$
}
+
+ @SuppressWarnings("restriction")
+ public static IType getReturnType(IASTFunctionDefinition func) {
+ // We could do this with public API (func.getDeclarator().getName().resolveBinding().getType()
+ // .getReturnType()), but that would trigger resolution of the parameter types as well,
+ // which is needless extra work.
+ if (func instanceof ICPPASTFunctionDefinition) {
+ return CPPVisitor.createType(func.getDeclarator(),
+ CPPVisitor.RESOLVE_PLACEHOLDERS | CPPVisitor.ONLY_RETURN_TYPE);
+ }
+ return CVisitor.createType(func.getDeclarator(), CVisitor.ONLY_RETURN_TYPE);
+ }
}
diff --git a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java
index bc42a2cbf2..02adada820 100644
--- a/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java
+++ b/codan/org.eclipse.cdt.codan.core.tests/src/org/eclipse/cdt/codan/core/internal/checkers/ReturnCheckerTest.java
@@ -453,4 +453,9 @@ public class ReturnCheckerTest extends CheckerTestCase {
public void testDoubleSemicolonInSwitchCase_455828() throws Exception {
checkSampleAboveCpp();
}
+
+ // auto f() {}
+ public void testReturnTypeDeduction_540112() throws Exception {
+ checkSampleAboveCpp();
+ }
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java
index 0c9a244d67..8e5d92a616 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java
@@ -120,6 +120,12 @@ import org.eclipse.cdt.internal.core.parser.util.ContentAssistMatcherFactory;
public class CVisitor extends ASTQueries {
private static final CBasicType UNSIGNED_LONG_INT = new CBasicType(Kind.eInt, IBasicType.IS_LONG | IBasicType.IS_UNSIGNED);
+ // Flags for createType().
+
+ // Given a function declarator, compute only the return type rather than
+ // the entire function type.
+ public static final int ONLY_RETURN_TYPE = 0x1;
+
public static class CollectProblemsAction extends ASTVisitor {
{
shouldVisitDeclarations = true;
@@ -1217,6 +1223,9 @@ public class CVisitor extends ASTQueries {
* @return the IType of the IASTDeclarator parameter
*/
public static IType createType(IASTDeclarator declarator) {
+ return createType(declarator, 0);
+ }
+ public static IType createType(IASTDeclarator declarator, int flags) {
IASTDeclSpecifier declSpec = null;
IASTNode node = declarator.getParent();
@@ -1238,7 +1247,7 @@ public class CVisitor extends ASTQueries {
boolean isParameter = (node instanceof IASTParameterDeclaration || node.getParent() instanceof ICASTKnRFunctionDeclarator);
IType type = createType((ICASTDeclSpecifier) declSpec);
- type = createType(type, declarator);
+ type = createType(type, declarator, flags);
if (isParameter) {
IType paramType = type;
@@ -1271,8 +1280,8 @@ public class CVisitor extends ASTQueries {
return createType(typeId.getAbstractDeclarator());
}
- public static IType createType(IType baseType, IASTDeclarator declarator) {
- if (declarator instanceof IASTFunctionDeclarator)
+ public static IType createType(IType baseType, IASTDeclarator declarator, int flags) {
+ if (((flags & ONLY_RETURN_TYPE) == 0) && declarator instanceof IASTFunctionDeclarator)
return createType(baseType, (IASTFunctionDeclarator) declarator);
IType type = baseType;
@@ -1282,7 +1291,7 @@ public class CVisitor extends ASTQueries {
IASTDeclarator nested = declarator.getNestedDeclarator();
if (nested != null) {
- return createType(type, nested);
+ return createType(type, nested, flags);
}
return type;
}
@@ -1340,7 +1349,7 @@ public class CVisitor extends ASTQueries {
IASTDeclarator nested = declarator.getNestedDeclarator();
if (nested != null) {
- return createType(type, nested);
+ return createType(type, nested, 0);
}
return type;
}
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
index f71a7bb68d..a0590edfb7 100644
--- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
+++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java
@@ -249,8 +249,14 @@ public class CPPVisitor extends ASTQueries {
public static final IASTInitializerClause[] NO_ARGS = {};
// Flags for createType().
+
+ // Attempt to resolve placeholders ('auto' and 'decltype(auto)').
public static final int RESOLVE_PLACEHOLDERS = 0x1;
+ // Given a function declarator, compute only the return type rather than
+ // the entire function type.
+ public static final int ONLY_RETURN_TYPE = 0x2;
+
// Common combinations of flags.
public static final int DO_NOT_RESOLVE_PLACEHOLDERS = 0;
@@ -2149,7 +2155,7 @@ public class CPPVisitor extends ASTQueries {
IType type = createType(declSpec);
type = makeConstIfConstexpr(type, declSpec, declarator);
- type = createType(type, declarator);
+ type = createType(type, declarator, flags);
// C++ specification 8.3.4.3 and 8.5.1.4
IASTNode initClause= declarator.getInitializer();
@@ -2537,6 +2543,10 @@ public class CPPVisitor extends ASTQueries {
}
if (returnType != null) {
+ if ((flags & ONLY_RETURN_TYPE) != 0) {
+ return returnType;
+ }
+
// 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.
@@ -2601,7 +2611,7 @@ public class CPPVisitor extends ASTQueries {
type = qualifyType(type, declSpec);
type = makeConstIfConstexpr(type, declSpec, declarator);
// Ignore function declarator because we already handled that in createAutoFunctionType().
- return createType(type, declarator, true /* ignore function declarator */);
+ return createType(type, declarator, ONLY_RETURN_TYPE);
}
private static IType makeConstIfConstexpr(IType type, IASTDeclSpecifier declSpec, IASTDeclarator declarator) {
@@ -2621,11 +2631,11 @@ public class CPPVisitor extends ASTQueries {
}
private static IType createType(IType baseType, IASTDeclarator declarator) {
- return createType(baseType, declarator, false);
+ return createType(baseType, declarator, 0);
}
- private static IType createType(IType baseType, IASTDeclarator declarator, boolean ignoreFunctionDeclarator) {
- if (!ignoreFunctionDeclarator && declarator instanceof ICPPASTFunctionDeclarator)
+ private static IType createType(IType baseType, IASTDeclarator declarator, int flags) {
+ if (((flags & ONLY_RETURN_TYPE) == 0) && declarator instanceof ICPPASTFunctionDeclarator)
return createFunctionType(baseType, (ICPPASTFunctionDeclarator) declarator);
IType type = baseType;

Back to the top