mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-30 20:35:38 +02:00
Bug 527553: Detect invalid decltype(auto) with a type specifier
The evaluated type of 'decltype(auto)' in combination with const and/or volatile will be a ProblemType since this is not valid code. The patch also contains a checker to give the user a visual feedback. Note: A proposed quick-fix has been removed after a short discussion. Change-Id: I8760ed0ac28e28529ab30516accac9c0413c87d9 Signed-off-by: Hansruedi Patzen <hansruedi.patzen@hsr.ch>
This commit is contained in:
parent
89d45ef7fd
commit
a4dcbbaf15
7 changed files with 296 additions and 0 deletions
|
@ -127,3 +127,7 @@ problem.description.UnusedStaticFunctionProblem = Finds static functions which c
|
|||
problem.messagePattern.UnusedStaticFunctionProblem = Unused static function ''{0}''
|
||||
problem.name.UnusedStaticFunctionProblem = Unused static function
|
||||
|
||||
checker.name.DecltypeAutoChecker = Invalid 'decltype(auto)' specifier checker
|
||||
problem.name.DecltypeAutoProblem = Invalid 'decltype(auto)' specifier
|
||||
problem.messagePattern.DecltypeAutoProblem = Combining 'decltype(auto)' with other type specifiers is not allowed
|
||||
problem.description.DecltypeAutoProblem = This rule will flag 'decltype(auto)' if combined with other type specifiers
|
||||
|
|
|
@ -423,6 +423,21 @@
|
|||
messagePattern="Sequence ''/*'' used inside the comment"
|
||||
name="Nesting comments">
|
||||
</problem>
|
||||
</checker>
|
||||
<checker
|
||||
class="org.eclipse.cdt.codan.internal.checkers.DecltypeAutoChecker"
|
||||
id="org.eclipse.cdt.codan.internal.checkers.DecltypeAutoChecker"
|
||||
name="%checker.name.DecltypeAutoChecker">
|
||||
<problem
|
||||
category="org.eclipse.cdt.codan.core.categories.ProgrammingProblems"
|
||||
defaultEnabled="true"
|
||||
defaultSeverity="Error"
|
||||
description="%problem.description.DecltypeAutoProblem"
|
||||
id="org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem"
|
||||
markerType="org.eclipse.cdt.codan.core.codanProblem"
|
||||
messagePattern="%problem.messagePattern.DecltypeAutoProblem"
|
||||
name="%problem.name.DecltypeAutoProblem">
|
||||
</problem>
|
||||
</checker>
|
||||
</extension>
|
||||
</plugin>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Institute for Software, HSR Hochschule fuer Technik
|
||||
* Rapperswil, University of applied sciences.
|
||||
* 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.codan.internal.checkers;
|
||||
|
||||
import org.eclipse.cdt.codan.core.cxx.model.AbstractIndexAstChecker;
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTSimpleDeclSpecifier;
|
||||
|
||||
public class DecltypeAutoChecker extends AbstractIndexAstChecker {
|
||||
public static final String ERR_ID = "org.eclipse.cdt.codan.internal.checkers.DecltypeAutoProblem"; //$NON-NLS-1$
|
||||
|
||||
@Override
|
||||
public boolean runInEditor() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processAst(IASTTranslationUnit ast) {
|
||||
ast.accept(new ASTVisitor() {
|
||||
{
|
||||
shouldVisitDeclSpecifiers = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTDeclSpecifier specifier) {
|
||||
if (specifier instanceof ICPPASTSimpleDeclSpecifier) {
|
||||
if (((ICPPASTSimpleDeclSpecifier) specifier).getType() == ICPPASTSimpleDeclSpecifier.t_decltype_auto) {
|
||||
if (specifier.isConst() || specifier.isVolatile()) {
|
||||
reportProblem(ERR_ID, specifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2017 Institute for Software, HSR Hochschule fuer Technik
|
||||
* Rapperswil, University of applied sciences.
|
||||
* 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.codan.core.internal.checkers;
|
||||
|
||||
import org.eclipse.cdt.codan.core.tests.CheckerTestCase;
|
||||
import org.eclipse.cdt.codan.internal.checkers.DecltypeAutoChecker;
|
||||
|
||||
/**
|
||||
* Test for {@link DecltypeAutoChecker} class
|
||||
*/
|
||||
public class DecltypeAutoCheckerTest extends CheckerTestCase {
|
||||
|
||||
public static final String ERR_ID = DecltypeAutoChecker.ERR_ID;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
enableProblems(ERR_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCpp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// int i { 42 }
|
||||
// decltype(i) k = i;
|
||||
public void testDecltypeExpressionVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrorsOfKind(ERR_ID);
|
||||
}
|
||||
|
||||
// int i { 42 }
|
||||
// decltype(i) volatile k = i;
|
||||
public void testDecltypeExpressionVolatileVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrorsOfKind(ERR_ID);
|
||||
}
|
||||
|
||||
// int i { 42 }
|
||||
// decltype(i) const k = i;
|
||||
public void testDecltypeExpressionConstVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrorsOfKind(ERR_ID);
|
||||
}
|
||||
|
||||
// int i { 42 }
|
||||
// decltype(i) const volatile k = i;
|
||||
public void testDecltypeExpressionCVVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrorsOfKind(ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) i { 42 };
|
||||
public void testDecltypeAutoVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrorsOfKind(ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) const i { 42 };
|
||||
public void testDecltypeAutoConstVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) volatile i { 42 };
|
||||
public void testDecltypeAutoVolatileVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) const volatile i { 42 };
|
||||
public void testDecltypeAutoCVVariable() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// void foo() {
|
||||
// decltype(auto) const i { 42 };
|
||||
// }
|
||||
public void testDecltypeAutoConstVariablInsideFunction() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(2, ERR_ID);
|
||||
}
|
||||
|
||||
// void foo() {
|
||||
// decltype(auto) volatile i { 42 };
|
||||
// }
|
||||
public void testDecltypeAutoVolatileVariableInsideFunction() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(2, ERR_ID);
|
||||
}
|
||||
|
||||
// void foo() {
|
||||
// decltype(auto) const volatile i { 42 };
|
||||
// }
|
||||
public void testDecltypeAutoCVVariableInsideFunction() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(2, ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) foo() {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrorsOfKind(ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) const foo() {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoConstReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) volatile foo() {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoVolatileReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// decltype(auto) const volatile foo() {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoCVReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoTrailingReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkNoErrorsOfKind(ERR_ID);
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) const {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoConstTrailingReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) volatile {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoVolatileTrailingReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) const volatile {
|
||||
// return 42;
|
||||
// }
|
||||
public void testDecltypeAutoCVTrailingReturnType() throws Exception {
|
||||
loadCodeAndRun(getAboveComment());
|
||||
checkErrorLine(1, ERR_ID);
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ import org.eclipse.cdt.codan.core.internal.checkers.CatchByReferenceTest;
|
|||
import org.eclipse.cdt.codan.core.internal.checkers.ClassMembersInitializationCheckerTest;
|
||||
import org.eclipse.cdt.codan.core.internal.checkers.CommentCheckerLineTests;
|
||||
import org.eclipse.cdt.codan.core.internal.checkers.CommentCheckerNestedTests;
|
||||
import org.eclipse.cdt.codan.core.internal.checkers.DecltypeAutoCheckerTest;
|
||||
import org.eclipse.cdt.codan.core.internal.checkers.FormatStringCheckerTest;
|
||||
import org.eclipse.cdt.codan.core.internal.checkers.NonVirtualDestructorCheckerTest;
|
||||
import org.eclipse.cdt.codan.core.internal.checkers.ProblemBindingCheckerTest;
|
||||
|
@ -66,6 +67,7 @@ public class AutomatedIntegrationSuite extends TestSuite {
|
|||
suite.addTestSuite(CaseBreakCheckerTest.class);
|
||||
suite.addTestSuite(CatchByReferenceTest.class);
|
||||
suite.addTestSuite(ClassMembersInitializationCheckerTest.class);
|
||||
suite.addTestSuite(DecltypeAutoCheckerTest.class);
|
||||
suite.addTestSuite(FormatStringCheckerTest.class);
|
||||
suite.addTestSuite(NonVirtualDestructorCheckerTest.class);
|
||||
suite.addTestSuite(ProblemBindingCheckerTest.class);
|
||||
|
|
|
@ -12268,6 +12268,9 @@ public class AST2CPPTests extends AST2CPPTestBase {
|
|||
// decltype(auto) j{42}; // Valid since C++17: decltype(j) is int
|
||||
// decltype(auto) k = new decltype(auto)(1L); // decltype(j) is long int *
|
||||
// decltype(auto) l; // Error - missing initializer.
|
||||
// decltype(auto) const m = 42; // Error - decltype(auto) does not allow type specifiers. Bug 527553
|
||||
// decltype(auto) volatile n = 42; // Error - decltype(auto) does not allow type specifiers. Bug 527553
|
||||
// decltype(auto) const volatile o = 42; // Error - decltype(auto) does not allow type specifiers. Bug 527553
|
||||
public void testDecltypeAutoVariableTypes_482225() throws Exception {
|
||||
String code = getAboveComment();
|
||||
BindingAssertionHelper bh = new AST2AssertionHelper(code, true);
|
||||
|
@ -12306,6 +12309,54 @@ public class AST2CPPTests extends AST2CPPTestBase {
|
|||
ICPPVariable l = bh.assertNonProblem("l;", 1);
|
||||
IProblemType lType = (IProblemType) l.getType();
|
||||
assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE, lType.getID());
|
||||
|
||||
ICPPVariable m = bh.assertNonProblem("m =", 1);
|
||||
IProblemType mType = (IProblemType) m.getType();
|
||||
assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE, mType.getID());
|
||||
|
||||
ICPPVariable n = bh.assertNonProblem("n =", 1);
|
||||
IProblemType nType = (IProblemType) n.getType();
|
||||
assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE, nType.getID());
|
||||
|
||||
ICPPVariable o = bh.assertNonProblem("o =", 1);
|
||||
IProblemType oType = (IProblemType) o.getType();
|
||||
assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE, oType.getID());
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) const {
|
||||
// return 23.0;
|
||||
// }
|
||||
// auto a = foo();
|
||||
public void testDecltypeAutoTrailingReturnTypeConst_527553() throws Exception {
|
||||
String code = getAboveComment();
|
||||
BindingAssertionHelper bh = new AST2AssertionHelper(code, true);
|
||||
ICPPVariable a = bh.assertNonProblem("a =", 1);
|
||||
IProblemType aType = (IProblemType) a.getType();
|
||||
assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE, aType.getID());
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) volatile {
|
||||
// return 23.0;
|
||||
// }
|
||||
// auto a = foo();
|
||||
public void testDecltypeAutoTrailingReturnTypeVolatile_527553() throws Exception {
|
||||
String code = getAboveComment();
|
||||
BindingAssertionHelper bh = new AST2AssertionHelper(code, true);
|
||||
ICPPVariable a = bh.assertNonProblem("a =", 1);
|
||||
IProblemType aType = (IProblemType) a.getType();
|
||||
assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_AUTO_TYPE, aType.getID());
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) const {
|
||||
// return 23.0;
|
||||
// }
|
||||
// decltype(auto) a = foo();
|
||||
public void testDecltypeAutoTrailingReturnTypeConstDecltype_527553() throws Exception {
|
||||
String code = getAboveComment();
|
||||
BindingAssertionHelper bh = new AST2AssertionHelper(code, true);
|
||||
ICPPVariable a = bh.assertNonProblem("a =", 1);
|
||||
IProblemType aType = (IProblemType) a.getType();
|
||||
assertEquals(ISemanticProblem.TYPE_CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE, aType.getID());
|
||||
}
|
||||
|
||||
// auto foo() -> decltype(auto) {
|
||||
|
|
|
@ -2270,6 +2270,10 @@ public class CPPVisitor extends ASTQueries {
|
|||
// 'decltype(auto)' cannot be combined with * or & the way 'auto' can.
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
if (declSpec.isConst() || declSpec.isVolatile()) {
|
||||
// 'decltype(auto)' cannot be combined with any type specifiers. [dcl.type.auto.deduct]
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
if (autoInitClause instanceof IASTExpression) {
|
||||
return getDeclType((IASTExpression) autoInitClause);
|
||||
} else {
|
||||
|
@ -2392,6 +2396,10 @@ public class CPPVisitor extends ASTQueries {
|
|||
// 'decltype(auto)' cannot be combined with * or & the way 'auto' can.
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
if (autoDeclSpec.isConst() || autoDeclSpec.isVolatile()) {
|
||||
// 'decltype(auto)' cannot be combined with any type specifiers. [dcl.type.auto.deduct]
|
||||
return ProblemType.CANNOT_DEDUCE_DECLTYPE_AUTO_TYPE;
|
||||
}
|
||||
return CPPSemantics.getDeclTypeForEvaluation(returnEval);
|
||||
} else /* auto */ {
|
||||
return createAutoType(returnEval, autoDeclSpec, autoDeclarator);
|
||||
|
|
Loading…
Add table
Reference in a new issue