mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 14:42:11 +02:00
Bug 546173 - Add a check for returning of local variable addresses
Change-Id: Ief17af55c20b6e075381fa22a9208b7dfa67ec0b Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
This commit is contained in:
parent
d0d6f57a50
commit
6504d1a917
4 changed files with 249 additions and 3 deletions
|
@ -48,6 +48,9 @@ problem.name.UnusedReturnValue = Unused return value
|
||||||
problem.description.NoReturn = No return statement in a function which is declared to return value
|
problem.description.NoReturn = No return statement in a function which is declared to return value
|
||||||
problem.messagePattern.NoReturn = No return, in function returning non-void
|
problem.messagePattern.NoReturn = No return, in function returning non-void
|
||||||
problem.name.NoReturn = No return
|
problem.name.NoReturn = No return
|
||||||
|
problem.description.LocalVarReturn = Returning the address of a local variable
|
||||||
|
problem.messagePattern.LocalVarReturn = Returning the address of local variable ''{0}''
|
||||||
|
problem.name.LocalVarReturn = Returning the address of a local variable
|
||||||
checker.name.FormatString = Format String
|
checker.name.FormatString = Format String
|
||||||
problem.description.FormatString = Finds statements lead to format string vulnerability (e.g. 'char[5] str; scanf("%10s", str);'\u0020
|
problem.description.FormatString = Finds statements lead to format string vulnerability (e.g. 'char[5] str; scanf("%10s", str);'\u0020
|
||||||
problem.messagePattern.FormatString = Format string vulnerability in ''{0}''
|
problem.messagePattern.FormatString = Format string vulnerability in ''{0}''
|
||||||
|
|
|
@ -119,6 +119,15 @@
|
||||||
messagePattern="%problem.messagePattern.NoReturn"
|
messagePattern="%problem.messagePattern.NoReturn"
|
||||||
name="%problem.name.NoReturn">
|
name="%problem.name.NoReturn">
|
||||||
</problem>
|
</problem>
|
||||||
|
<problem
|
||||||
|
category="org.eclipse.cdt.codan.core.categories.ProgrammingProblems"
|
||||||
|
defaultEnabled="false"
|
||||||
|
defaultSeverity="Warning"
|
||||||
|
description="%problem.description.LocalVarReturn"
|
||||||
|
id="org.eclipse.cdt.codan.checkers.localvarreturn"
|
||||||
|
messagePattern="%problem.messagePattern.LocalVarReturn"
|
||||||
|
name="%problem.name.LocalVarReturn">
|
||||||
|
</problem>
|
||||||
</checker>
|
</checker>
|
||||||
<checker
|
<checker
|
||||||
class="org.eclipse.cdt.codan.internal.checkers.ProblemBindingChecker"
|
class="org.eclipse.cdt.codan.internal.checkers.ProblemBindingChecker"
|
||||||
|
|
|
@ -17,7 +17,9 @@ package org.eclipse.cdt.codan.internal.checkers;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.codan.checkers.CodanCheckersActivator;
|
||||||
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
|
import org.eclipse.cdt.codan.core.cxx.CxxAstUtils;
|
||||||
import org.eclipse.cdt.codan.core.cxx.model.AbstractAstFunctionChecker;
|
import org.eclipse.cdt.codan.core.cxx.model.AbstractAstFunctionChecker;
|
||||||
import org.eclipse.cdt.codan.core.model.IProblem;
|
import org.eclipse.cdt.codan.core.model.IProblem;
|
||||||
|
@ -28,32 +30,51 @@ import org.eclipse.cdt.codan.core.model.cfg.IControlFlowGraph;
|
||||||
import org.eclipse.cdt.codan.core.model.cfg.IExitNode;
|
import org.eclipse.cdt.codan.core.model.cfg.IExitNode;
|
||||||
import org.eclipse.cdt.codan.internal.core.cfg.ControlFlowGraph;
|
import org.eclipse.cdt.codan.internal.core.cfg.ControlFlowGraph;
|
||||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.EScopeKind;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTCastExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTConditionalExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTDeclaration;
|
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.IASTDoStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
import org.eclipse.cdt.core.dom.ast.IASTExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTFieldReference;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTForStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTGotoStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTIdExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTIfStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
|
import org.eclipse.cdt.core.dom.ast.IASTInitializerClause;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTPointerOperator;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTReturnStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclSpecifier;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTSwitchStatement;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTTypeId;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTWhileStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBasicType;
|
import org.eclipse.cdt.core.dom.ast.IBasicType;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IFunction;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IParameter;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IPointerType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||||
import org.eclipse.cdt.core.dom.ast.IType;
|
import org.eclipse.cdt.core.dom.ast.IType;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IVariable;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition;
|
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.ICPPASTLambdaExpression;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTReferenceOperator;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTryBlockStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPField;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
|
||||||
|
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The checker suppose to find issue related to mismatched return value/function
|
* The checker suppose to find issue related to mismatched return value/function
|
||||||
|
@ -62,16 +83,115 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPTemplates;
|
||||||
* <li>Function declared as returning void has non-void return
|
* <li>Function declared as returning void has non-void return
|
||||||
* <li>Function declared as returning non-void has no return (requires control flow graph)
|
* <li>Function declared as returning non-void has no return (requires control flow graph)
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("restriction")
|
||||||
public class ReturnChecker extends AbstractAstFunctionChecker {
|
public class ReturnChecker extends AbstractAstFunctionChecker {
|
||||||
public static final String PARAM_IMPLICIT = "implicit"; //$NON-NLS-1$
|
public static final String PARAM_IMPLICIT = "implicit"; //$NON-NLS-1$
|
||||||
public static final String RET_NO_VALUE_ID = "org.eclipse.cdt.codan.checkers.noreturn"; //$NON-NLS-1$
|
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_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$
|
public static final String RET_NORET_ID = "org.eclipse.cdt.codan.checkers.errnoreturn"; //$NON-NLS-1$
|
||||||
|
public static final String RET_LOCAL_ID = "org.eclipse.cdt.codan.checkers.localvarreturn"; //$NON-NLS-1$
|
||||||
|
|
||||||
private IType cachedReturnType = null;
|
private IType cachedReturnType = null;
|
||||||
|
|
||||||
|
private enum RetType {
|
||||||
|
BY_REF, BY_PTR
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ReturnTypeAnalyzer {
|
||||||
|
private RetType retType;
|
||||||
|
private Stack<Integer> innermostOp;
|
||||||
|
|
||||||
|
public ReturnTypeAnalyzer(RetType t) {
|
||||||
|
retType = t;
|
||||||
|
innermostOp = new Stack<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public RetType getType() {
|
||||||
|
return retType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visit(IASTInitializerClause expr) {
|
||||||
|
if (expr instanceof IASTCastExpression) {
|
||||||
|
visit((IASTCastExpression) expr);
|
||||||
|
} else if (expr instanceof IASTConditionalExpression) {
|
||||||
|
visit((IASTConditionalExpression) expr);
|
||||||
|
} else if (expr instanceof IASTIdExpression) {
|
||||||
|
visit((IASTIdExpression) expr);
|
||||||
|
} else if (expr instanceof IASTUnaryExpression) {
|
||||||
|
visit((IASTUnaryExpression) expr);
|
||||||
|
} else if (expr instanceof IASTFieldReference) {
|
||||||
|
visit((IASTFieldReference) expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visit(IASTFieldReference expr) {
|
||||||
|
visit(expr.getFieldOwner());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visit(IASTCastExpression expr) {
|
||||||
|
IASTTypeId id = expr.getTypeId();
|
||||||
|
IASTDeclarator declarator = id.getAbstractDeclarator();
|
||||||
|
IASTPointerOperator[] ptr = declarator.getPointerOperators();
|
||||||
|
if (ptr.length > 0 && ptr[0] instanceof ICPPASTReferenceOperator) {
|
||||||
|
innermostOp.push(IASTUnaryExpression.op_amper);
|
||||||
|
}
|
||||||
|
visit(expr.getOperand());
|
||||||
|
if (ptr.length > 0 && ptr[0] instanceof ICPPASTReferenceOperator) {
|
||||||
|
innermostOp.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visit(IASTConditionalExpression expr) {
|
||||||
|
visit(expr.getPositiveResultExpression());
|
||||||
|
visit(expr.getNegativeResultExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visit(IASTIdExpression expr) {
|
||||||
|
IBinding binding = expr.getName().resolveBinding();
|
||||||
|
if (binding instanceof IVariable && !(binding instanceof IParameter) && !(binding instanceof ICPPField)) {
|
||||||
|
Integer op = null;
|
||||||
|
if (!innermostOp.empty())
|
||||||
|
op = innermostOp.peek();
|
||||||
|
IType t = ((IVariable) binding).getType();
|
||||||
|
if (((IVariable) binding).isStatic()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = SemanticUtil.getNestedType(t, SemanticUtil.TDEF);
|
||||||
|
if (retType == RetType.BY_REF && !(t instanceof ICPPReferenceType)) {
|
||||||
|
if (t instanceof IPointerType && op != null && op == IASTUnaryExpression.op_star) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
IScope scope = binding.getScope();
|
||||||
|
if (scope.getKind() == EScopeKind.eLocal) {
|
||||||
|
reportProblem(RET_LOCAL_ID, expr, binding.getName());
|
||||||
|
}
|
||||||
|
} catch (DOMException e) {
|
||||||
|
CodanCheckersActivator.log(e);
|
||||||
|
}
|
||||||
|
} else if (retType == RetType.BY_PTR && op != null && op == IASTUnaryExpression.op_amper) {
|
||||||
|
try {
|
||||||
|
IScope scope = binding.getScope();
|
||||||
|
if (scope.getKind() == EScopeKind.eLocal) {
|
||||||
|
reportProblem(RET_LOCAL_ID, expr, binding.getName());
|
||||||
|
}
|
||||||
|
} catch (DOMException e) {
|
||||||
|
CodanCheckersActivator.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void visit(IASTUnaryExpression expr) {
|
||||||
|
innermostOp.push(expr.getOperator());
|
||||||
|
visit(expr.getOperand());
|
||||||
|
innermostOp.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class ReturnStmpVisitor extends ASTVisitor {
|
class ReturnStmpVisitor extends ASTVisitor {
|
||||||
private final IASTFunctionDefinition func;
|
private final IASTFunctionDefinition func;
|
||||||
|
private final ReturnTypeAnalyzer analyzer;
|
||||||
boolean hasret;
|
boolean hasret;
|
||||||
|
|
||||||
ReturnStmpVisitor(IASTFunctionDefinition func) {
|
ReturnStmpVisitor(IASTFunctionDefinition func) {
|
||||||
|
@ -80,6 +200,24 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
|
||||||
shouldVisitExpressions = true;
|
shouldVisitExpressions = true;
|
||||||
this.func = func;
|
this.func = func;
|
||||||
this.hasret = false;
|
this.hasret = false;
|
||||||
|
IBinding binding = func.getDeclarator().getName().resolveBinding();
|
||||||
|
if (binding instanceof IFunction) {
|
||||||
|
IType retType = SemanticUtil.getNestedType(((IFunction) binding).getType().getReturnType(),
|
||||||
|
SemanticUtil.TDEF);
|
||||||
|
if (retType instanceof ICPPReferenceType) {
|
||||||
|
analyzer = new ReturnTypeAnalyzer(RetType.BY_REF);
|
||||||
|
} else if (retType instanceof IPointerType) {
|
||||||
|
analyzer = new ReturnTypeAnalyzer(RetType.BY_PTR);
|
||||||
|
} else
|
||||||
|
analyzer = null;
|
||||||
|
} else
|
||||||
|
analyzer = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RetType getType() {
|
||||||
|
if (analyzer != null)
|
||||||
|
return analyzer.getType();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -110,6 +248,8 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
|
||||||
if (checkImplicitReturn(RET_NO_VALUE_ID) || isExplicitReturn(func)) {
|
if (checkImplicitReturn(RET_NO_VALUE_ID) || isExplicitReturn(func)) {
|
||||||
if (returnValue == null)
|
if (returnValue == null)
|
||||||
reportProblem(RET_NO_VALUE_ID, ret);
|
reportProblem(RET_NO_VALUE_ID, ret);
|
||||||
|
else if (analyzer != null)
|
||||||
|
analyzer.visit(returnValue);
|
||||||
}
|
}
|
||||||
} else if (returnKind == ReturnTypeKind.Void) {
|
} else if (returnKind == ReturnTypeKind.Void) {
|
||||||
if (returnValue instanceof IASTExpression) {
|
if (returnValue instanceof IASTExpression) {
|
||||||
|
@ -190,7 +330,6 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
|
||||||
// TODO: Any reason not to just expose getDeadNodes() in IControlFlowGraph?
|
// TODO: Any reason not to just expose getDeadNodes() in IControlFlowGraph?
|
||||||
public Collection<IBasicBlock> getDeadBlocks(IASTFunctionDefinition func) {
|
public Collection<IBasicBlock> getDeadBlocks(IASTFunctionDefinition func) {
|
||||||
IControlFlowGraph graph = getModelCache().getControlFlowGraph(func);
|
IControlFlowGraph graph = getModelCache().getControlFlowGraph(func);
|
||||||
|
@ -263,7 +402,6 @@ public class ReturnChecker extends AbstractAstFunctionChecker {
|
||||||
* @param func the function to check
|
* @param func the function to check
|
||||||
* @return {@code true} if the function has a non void return type
|
* @return {@code true} if the function has a non void return type
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("restriction")
|
|
||||||
private ReturnTypeKind getReturnTypeKind(IASTFunctionDefinition func) {
|
private ReturnTypeKind getReturnTypeKind(IASTFunctionDefinition func) {
|
||||||
if (isConstructorDestructor(func))
|
if (isConstructorDestructor(func))
|
||||||
return ReturnTypeKind.Void;
|
return ReturnTypeKind.Void;
|
||||||
|
|
|
@ -26,7 +26,8 @@ public class ReturnCheckerTest extends CheckerTestCase {
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
enableProblems(ReturnChecker.RET_NORET_ID, ReturnChecker.RET_ERR_VALUE_ID, ReturnChecker.RET_NO_VALUE_ID);
|
enableProblems(ReturnChecker.RET_NORET_ID, ReturnChecker.RET_ERR_VALUE_ID, ReturnChecker.RET_NO_VALUE_ID,
|
||||||
|
ReturnChecker.RET_LOCAL_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -527,4 +528,99 @@ public class ReturnCheckerTest extends CheckerTestCase {
|
||||||
public void testNoReturnWithGoto_Bug492878() throws Exception {
|
public void testNoReturnWithGoto_Bug492878() throws Exception {
|
||||||
checkSampleAboveCpp();
|
checkSampleAboveCpp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// int& bar() {
|
||||||
|
// int a = 0;
|
||||||
|
// return a; //error here
|
||||||
|
// }
|
||||||
|
public void testReturnByRef_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// int* bar() {
|
||||||
|
// int a = 0;
|
||||||
|
// return &a; //error here
|
||||||
|
// }
|
||||||
|
public void testReturnByPtr_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// int& bar() {
|
||||||
|
// int a = 0;
|
||||||
|
// return reinterpret_cast<int&>(a); //error here
|
||||||
|
// }
|
||||||
|
public void testReturnByCastRef_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// int* bar() {
|
||||||
|
// int a = 0;
|
||||||
|
// return reinterpret_cast<int*>(a);
|
||||||
|
// }
|
||||||
|
public void testReturnByCastPtr_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// int* bar() {
|
||||||
|
// int a = 0, b = 0;
|
||||||
|
// bool cond = true;
|
||||||
|
// return cond ? &a : //error here
|
||||||
|
// &b; //error here
|
||||||
|
// }
|
||||||
|
public void testReturnByTernary_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// struct S { int a; }
|
||||||
|
// int& bar() {
|
||||||
|
// struct S s;
|
||||||
|
// return s.a; //error here
|
||||||
|
// }
|
||||||
|
public void testReturnLocalStructField_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// class Test {
|
||||||
|
// private:
|
||||||
|
// int field;
|
||||||
|
// public:
|
||||||
|
// int& bar() {
|
||||||
|
// return field;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testReturnClassField_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// class Test {
|
||||||
|
// private:
|
||||||
|
// int field;
|
||||||
|
// public:
|
||||||
|
// void foo(double*);
|
||||||
|
// void (Test::*bar())(double*) {
|
||||||
|
// return &Test::foo;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
public void testReturnClassMethod_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//int& foo() {
|
||||||
|
// int* a = new int;
|
||||||
|
// return *a;
|
||||||
|
//}
|
||||||
|
public void testReturnRefUsingDerefPtr_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//void foo() {
|
||||||
|
// int local;
|
||||||
|
// auto s = [&local]() {
|
||||||
|
// return &local; // ok
|
||||||
|
// };
|
||||||
|
// int* ptr = s();
|
||||||
|
//}
|
||||||
|
public void testReturnLambda_Bug546173() throws Exception {
|
||||||
|
checkSampleAboveCpp();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue