1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-05 08:46:02 +02:00

Do not allow structured binding initializer referencing introduced name (#241)

If name lookup ends up with a variable, additionally check if node being
resolved is part of the structured binding initializer introducing found
variable. If this is the case, produce problem binding and report structured
binding declaration error via codan.

This change also prevents infinite recursion trying to resolve auto type of
introduced variable while evaluating such problematic initializer.
This commit is contained in:
Igor V. Kovalenko 2023-01-28 18:54:09 +03:00 committed by GitHub
parent 2776d17014
commit fe7a9d7856
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 62 additions and 1 deletions

View file

@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: %Bundle-Name
Bundle-SymbolicName: org.eclipse.cdt.codan.checkers;singleton:=true
Bundle-Version: 3.5.0.qualifier
Bundle-Version: 3.5.100.qualifier
Bundle-Activator: org.eclipse.cdt.codan.checkers.CodanCheckersActivator
Require-Bundle: org.eclipse.core.runtime,
org.eclipse.core.resources,

View file

@ -113,6 +113,9 @@ problem.name.11 = Method cannot be resolved
problem.description.12 = Name resolution problem found by the indexer
problem.messagePattern.12 = Field ''{0}'' could not be resolved
problem.name.12 = Field cannot be resolved
problem.description.13 = Name resolution problem found by the indexer
problem.messagePattern.13 = Structured binding initializer expression refers to introduced name ''{0}''
problem.name.13 = Invalid structured binding declaration
checker.name.AbstractClassCreation = Abstract class cannot be instantiated
problem.name.AbstractClassCreation = Abstract class cannot be instantiated
problem.messagePattern.AbstractClassCreation = The type ''{0}'' must implement the inherited pure virtual method ''{1}''\u0020

View file

@ -273,6 +273,16 @@
messagePattern="%problem.messagePattern.12"
name="%problem.name.12">
</problem>
<problem
category="org.eclipse.cdt.codan.core.categories.CompilerErrors"
defaultEnabled="true"
defaultSeverity="Error"
description="%problem.description.13"
id="org.eclipse.cdt.codan.internal.checkers.StructuredBindingDeclarationProblem"
markerType="org.eclipse.cdt.codan.core.codanSemanticProblem"
messagePattern="%problem.messagePattern.13"
name="%problem.name.13">
</problem>
</checker>
<checker
class="org.eclipse.cdt.codan.internal.checkers.AssignmentToItselfChecker"

View file

@ -40,6 +40,7 @@ import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclarator;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLiteralExpression;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTStructuredBindingDeclaration;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction;
@ -64,6 +65,7 @@ public class ProblemBindingChecker extends AbstractIndexAstChecker {
public static String ERR_ID_FieldResolutionProblem = "org.eclipse.cdt.codan.internal.checkers.FieldResolutionProblem"; //$NON-NLS-1$
public static String ERR_ID_VariableResolutionProblem = "org.eclipse.cdt.codan.internal.checkers.VariableResolutionProblem"; //$NON-NLS-1$
public static String ERR_ID_Candidates = "org.eclipse.cdt.codan.internal.checkers.Candidates"; //$NON-NLS-1$
public static String ERR_ID_StructuredBindingDeclarationProblem = "org.eclipse.cdt.codan.internal.checkers.StructuredBindingDeclarationProblem"; //$NON-NLS-1$
@Override
public boolean runInEditor() {
@ -126,6 +128,22 @@ public class ProblemBindingChecker extends AbstractIndexAstChecker {
contextFlagsString);
return PROCESS_CONTINUE;
}
if (id == IProblemBinding.SEMANTIC_INVALID_STRUCTURED_BINDING_INITIALIZER) {
IASTNode problemNode = parentNode;
while (problemNode != null) {
if (problemNode instanceof ICPPASTStructuredBindingDeclaration) {
break;
}
problemNode = problemNode.getParent();
}
if (problemNode == null) {
// this should not happen because problem binding should be inside structured binding initializer subtree
problemNode = parentNode;
}
reportProblem(ERR_ID_StructuredBindingDeclarationProblem, problemNode,
parentNode.getRawSignature(), contextFlagsString);
return PROCESS_CONTINUE;
}
if (id == IProblemBinding.SEMANTIC_INVALID_REDECLARATION) {
reportProblem(ERR_ID_RedeclarationProblem, name, name.getRawSignature(),
contextFlagsString);

View file

@ -415,4 +415,12 @@ public class StructuredBindingTests extends AST2CPPTestBase {
assertEquals(IntegralValue.create(1), subvalues[0].getValue());
assertEquals(FloatingPointValue.create(2.0), subvalues[1].getValue());
}
//void f() {
// auto& [x] = x.y;
//}
public void testInvalidReferenceToIntroducedName() throws Exception {
BindingAssertionHelper ba = getAssertionHelper();
ba.assertProblem("x.y;", 1);
}
}

View file

@ -65,6 +65,8 @@ public interface IProblemBinding extends IBinding, IScope, IType, ISemanticProbl
public static final int SEMANTIC_RECURSION_IN_LOOKUP = BINDING_RECURSION_IN_LOOKUP;
/** @since 5.1 */
public static final int SEMANTIC_INVALID_TEMPLATE_ARGUMENTS = BINDING_INVALID_TEMPLATE_ARGUMENTS;
/** @since 8.1 */
public static final int SEMANTIC_INVALID_STRUCTURED_BINDING_INITIALIZER = BINDING_INVALID_STRUCTURED_BINDING_INITIALIZER;
/**
* @deprecated There may be additional problems.

View file

@ -37,6 +37,8 @@ public interface ISemanticProblem {
int BINDING_RECURSION_IN_LOOKUP = 14;
int BINDING_INVALID_TEMPLATE_ARGUMENTS = 15;
int BINDING_NO_CLASS = 16;
/** @since 8.1 */
int BINDING_INVALID_STRUCTURED_BINDING_INITIALIZER = 17;
int TYPE_NO_NAME = 10000;
int TYPE_UNRESOLVED_NAME = 10001;

View file

@ -409,6 +409,21 @@ public class CPPSemantics {
}
}
// If any name in the initializer refers to introduced names then declaration is ill-formed.
if (binding instanceof ICPPInternalBinding internalBinding && internalBinding.getDefinition() != null
&& internalBinding.getDefinition()
.getParent() instanceof ICPPASTStructuredBindingDeclaration declaration) {
IASTNode parent = lookupName.getParent();
while (parent != null) {
if (parent == declaration) {
binding = new ProblemBinding(lookupName, data.getLookupPoint(),
IProblemBinding.SEMANTIC_INVALID_STRUCTURED_BINDING_INITIALIZER, data.getFoundBindings());
break;
}
parent = parent.getParent();
}
}
if (binding instanceof IProblemBinding)
return binding;

View file

@ -93,6 +93,8 @@ public class ParserMessages {
return "ISemanticProblem.BINDING_INVALID_REDECLARATION";
case ISemanticProblem.BINDING_INVALID_REDEFINITION:
return "ISemanticProblem.BINDING_INVALID_REDEFINITION";
case ISemanticProblem.BINDING_INVALID_STRUCTURED_BINDING_INITIALIZER:
return "ISemanticProblem.BINDING_INVALID_STRUCTURED_BINDING_INITIALIZER";
case ISemanticProblem.BINDING_INVALID_TEMPLATE_ARGUMENTS:
return "ISemanticProblem.BINDING_INVALID_TEMPLATE_ARGUMENTS";
case ISemanticProblem.BINDING_INVALID_TYPE:

View file

@ -71,6 +71,7 @@ ISemanticProblem.BINDING_INVALID_REDECLARATION=Invalid redeclaration of the name
ISemanticProblem.BINDING_RECURSION_IN_LOOKUP=Recursion while looking up ''{0}''
ISemanticProblem.BINDING_MEMBER_DECLARATION_NOT_FOUND=A declaration could not be found for this member definition: {0}
ISemanticProblem.BINDING_INVALID_TEMPLATE_ARGUMENTS=A template id provides illegal arguments for the instantiation: {0}
ISemanticProblem.BINDING_INVALID_STRUCTURED_BINDING_INITIALIZER=Invalid structured binding initializer referencing introduced name ''{0}''
ISemanticProblem.TYPE_NO_NAME=Type specification lacks a name
ISemanticProblem.TYPE_UNRESOLVED_NAME=Type depends on an unresolved name