Skip to main content
aboutsummaryrefslogtreecommitdiffstats
path: root/codan
diff options
context:
space:
mode:
authorNathan Ridge2018-10-15 06:01:01 +0000
committerNathan Ridge2018-10-29 02:52:37 +0000
commita00346af224c6a60a70151908790272d54d58955 (patch)
tree8f8a27490fdeb86728661972cebfc278524b53d0 /codan
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
Diffstat (limited to 'codan')
-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
3 files changed, 36 insertions, 70 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 8b23febac16..a2b3389233d 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 ff9f1096118..7f992fc8858 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 bc42a2cbf2b..02adada820d 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();
+ }
}

Back to the top