mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 06:32:10 +02:00
Bug 484979 - Name resolution fixes for labels
Change-Id: Ic90a335bf9cb283dcf5a02e83839d955ad312593 Signed-off-by: Nathan Ridge <zeratul976@hotmail.com>
This commit is contained in:
parent
1b0fe3a41e
commit
ea73b8149c
7 changed files with 139 additions and 172 deletions
|
@ -7569,4 +7569,29 @@ public class AST2Tests extends AST2TestBase {
|
|||
// being incorrectly parsed as cast-expressions.
|
||||
parseAndCheckBindings(getAboveComment(), C);
|
||||
}
|
||||
|
||||
private void labelResolutionHelper(BindingAssertionHelper helper) {
|
||||
// Make sure existing labels are resolved correctly.
|
||||
ILabel label = helper.assertNonProblem("goto existent", "existent");
|
||||
assertEquals(1, helper.tu.getDeclarationsInAST(label).length);
|
||||
label = helper.assertNonProblem("&& existent", "existent");
|
||||
assertEquals(1, helper.tu.getDeclarationsInAST(label).length);
|
||||
|
||||
// Make sure non-existent labels are not resolved.
|
||||
helper.assertProblem("goto nonexistent", "nonexistent");
|
||||
helper.assertProblem("&& nonexistent", "nonexistent");
|
||||
}
|
||||
|
||||
// int main() {
|
||||
// existent:
|
||||
// int x;
|
||||
// goto existent;
|
||||
// goto nonexistent;
|
||||
// void* ref1 = && existent;
|
||||
// void* ref2 = && nonexistent;
|
||||
// }
|
||||
public void testLabelResolution_484979() throws Exception {
|
||||
labelResolutionHelper(getAssertionHelper(C));
|
||||
labelResolutionHelper(getAssertionHelper(CPP));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,13 @@ package org.eclipse.cdt.core.dom.ast;
|
|||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
public interface IASTLabelStatement extends IASTStatement, IASTNameOwner {
|
||||
/** @since 5.4 */
|
||||
/** @since 5.12 */
|
||||
public static final IASTLabelStatement[] EMPTY_ARRAY = {};
|
||||
/**
|
||||
* @since 5.4
|
||||
* @deprecated use {@link #EMPTY_ARRAY} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final IASTStatement[] EMPTY_LABEL_STATEMENT_ARRAY = {};
|
||||
|
||||
public static final ASTNodeProperty NAME = new ASTNodeProperty("IASTLabelStatement.NAME - name for IASTLabelStatement"); //$NON-NLS-1$
|
||||
|
@ -43,9 +49,11 @@ public interface IASTLabelStatement extends IASTStatement, IASTNameOwner {
|
|||
public IASTStatement getNestedStatement();
|
||||
|
||||
/**
|
||||
* @param s
|
||||
* Sets the statement following the label.
|
||||
*
|
||||
* @param statement the statement to set
|
||||
*/
|
||||
public void setNestedStatement(IASTStatement s);
|
||||
public void setNestedStatement(IASTStatement statement);
|
||||
|
||||
/**
|
||||
* @since 5.1
|
||||
|
|
|
@ -18,7 +18,13 @@ package org.eclipse.cdt.core.dom.ast;
|
|||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
public interface ILabel extends IBinding {
|
||||
/** @since 5.4 */
|
||||
/** @since 5.12 */
|
||||
public static final ILabel[] EMPTY_ARRAY = {};
|
||||
/**
|
||||
* @since 5.4
|
||||
* @deprecated use {@link #EMPTY_ARRAY} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static final IBinding[] EMPTY_LABEL_ARRAY = {};
|
||||
|
||||
/**
|
||||
|
|
|
@ -17,13 +17,18 @@ import org.eclipse.cdt.core.dom.ast.IASTDeclarator;
|
|||
import org.eclipse.cdt.core.dom.ast.IASTFieldDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDeclarator;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTName;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTUnaryExpression;
|
||||
import org.eclipse.cdt.core.dom.ast.IArrayType;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.ILabel;
|
||||
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.IType;
|
||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.c.CVisitor;
|
||||
import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor;
|
||||
|
||||
|
@ -137,25 +142,21 @@ public class ASTQueries {
|
|||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends IASTNode> T findAncestorWithType(IASTNode node, Class<T> type) {
|
||||
do {
|
||||
if (type.isInstance(node)) {
|
||||
return (T) node;
|
||||
}
|
||||
} while ((node = node.getParent()) != null);
|
||||
return null;
|
||||
while (node != null && !type.isInstance(node)) {
|
||||
node = node.getParent();
|
||||
}
|
||||
return (T) node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for the function enclosing the given node. May return <code>null</code>.
|
||||
*/
|
||||
public static IBinding findEnclosingFunction(IASTNode node) {
|
||||
while (node != null && !(node instanceof IASTFunctionDefinition)) {
|
||||
node= node.getParent();
|
||||
}
|
||||
if (node == null)
|
||||
IASTFunctionDefinition functionDefinition = findAncestorWithType(node, IASTFunctionDefinition.class);
|
||||
if (functionDefinition == null)
|
||||
return null;
|
||||
|
||||
IASTDeclarator dtor= findInnermostDeclarator(((IASTFunctionDefinition) node).getDeclarator());
|
||||
IASTDeclarator dtor= findInnermostDeclarator(functionDefinition.getDeclarator());
|
||||
if (dtor != null) {
|
||||
IASTName name= dtor.getName();
|
||||
if (name != null) {
|
||||
|
@ -226,4 +227,53 @@ public class ASTQueries {
|
|||
|
||||
return labelReference;
|
||||
}
|
||||
|
||||
private static class FindLabelsAction extends ASTVisitor {
|
||||
public IASTLabelStatement[] labels = IASTLabelStatement.EMPTY_ARRAY;
|
||||
|
||||
public FindLabelsAction() {
|
||||
shouldVisitStatements = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTStatement statement) {
|
||||
if (statement instanceof IASTLabelStatement) {
|
||||
labels = ArrayUtil.append(labels, (IASTLabelStatement) statement);
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
protected static ILabel[] getLabels(IASTFunctionDefinition functionDefinition) {
|
||||
FindLabelsAction action = new FindLabelsAction();
|
||||
|
||||
functionDefinition.accept(action);
|
||||
|
||||
ILabel[] result = ILabel.EMPTY_ARRAY;
|
||||
if (action.labels != null) {
|
||||
for (int i = 0; i < action.labels.length && action.labels[i] != null; i++) {
|
||||
IASTLabelStatement labelStatement = action.labels[i];
|
||||
IBinding binding = labelStatement.getName().resolveBinding();
|
||||
if (binding != null)
|
||||
result = ArrayUtil.append(result, (ILabel) binding);
|
||||
}
|
||||
}
|
||||
return ArrayUtil.trim(result);
|
||||
}
|
||||
|
||||
protected static IBinding resolveLabel(IASTName labelReference) {
|
||||
char[] labelName = labelReference.toCharArray();
|
||||
IASTFunctionDefinition functionDefinition = findAncestorWithType(labelReference,
|
||||
IASTFunctionDefinition.class);
|
||||
if (functionDefinition != null) {
|
||||
for (ILabel label : getLabels(functionDefinition)) {
|
||||
if (CharArrayUtils.equals(label.getNameCharArray(), labelName)) {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
// label not found
|
||||
return new ProblemBinding(labelReference, IProblemBinding.SEMANTIC_LABEL_STATEMENT_NOT_FOUND,
|
||||
labelName);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,18 +10,14 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom.parser.c;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ast.ASTVisitor;
|
||||
import org.eclipse.cdt.core.dom.ast.EScopeKind;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTFunctionDefinition;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTLabelStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTNode;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTStatement;
|
||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||
import org.eclipse.cdt.core.dom.ast.ILabel;
|
||||
import org.eclipse.cdt.core.dom.ast.IScope;
|
||||
import org.eclipse.cdt.core.dom.ast.c.ICFunctionScope;
|
||||
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||
|
||||
public class CFunctionScope extends CScope implements ICFunctionScope {
|
||||
public CFunctionScope(IASTFunctionDefinition function) {
|
||||
|
@ -46,37 +42,4 @@ public class CFunctionScope extends CScope implements ICFunctionScope {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ILabel[] getLabels() {
|
||||
FindLabelsAction action = new FindLabelsAction();
|
||||
|
||||
getPhysicalNode().accept(action);
|
||||
|
||||
ILabel[] result = null;
|
||||
if (action.labels != null) {
|
||||
for (int i = 0; i < action.labels.length && action.labels[i] != null; i++) {
|
||||
IASTLabelStatement labelStatement = action.labels[i];
|
||||
IBinding binding = labelStatement.getName().resolveBinding();
|
||||
if (binding != null)
|
||||
result = ArrayUtil.append(ILabel.class, result, (ILabel) binding);
|
||||
}
|
||||
}
|
||||
return ArrayUtil.trim(ILabel.class, result);
|
||||
}
|
||||
|
||||
static private class FindLabelsAction extends ASTVisitor {
|
||||
public IASTLabelStatement[] labels = null;
|
||||
|
||||
public FindLabelsAction() {
|
||||
shouldVisitStatements = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visit(IASTStatement statement) {
|
||||
if (statement instanceof IASTLabelStatement) {
|
||||
labels = ArrayUtil.append(IASTLabelStatement.class, labels, (IASTLabelStatement) statement);
|
||||
}
|
||||
return PROCESS_CONTINUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -462,16 +462,7 @@ public class CVisitor extends ASTQueries {
|
|||
IBinding binding = null;
|
||||
IASTNode parent = name.getParent();
|
||||
|
||||
// GNU Goto label reference
|
||||
//
|
||||
// void* labelPtr = &&foo; <-- label reference
|
||||
// foo:
|
||||
//
|
||||
boolean labelReference = isLabelReference(parent);
|
||||
|
||||
if (labelReference) {
|
||||
binding = createLabelReferenceBinding(name);
|
||||
} else if (parent instanceof CASTIdExpression) {
|
||||
if (parent instanceof CASTIdExpression) {
|
||||
binding = resolveBinding(parent);
|
||||
} else if (parent instanceof ICASTTypedefNameSpecifier) {
|
||||
binding = resolveBinding(parent);
|
||||
|
@ -486,8 +477,10 @@ public class CVisitor extends ASTQueries {
|
|||
binding = createBinding((ICASTCompositeTypeSpecifier) parent);
|
||||
} else if (parent instanceof ICASTElaboratedTypeSpecifier) {
|
||||
binding = createBinding((ICASTElaboratedTypeSpecifier) parent);
|
||||
} else if (parent instanceof IASTStatement) {
|
||||
binding = createBinding ((IASTStatement) parent);
|
||||
} else if (parent instanceof IASTGotoStatement) {
|
||||
binding = resolveBinding((IASTGotoStatement) parent);
|
||||
} else if (parent instanceof IASTLabelStatement) {
|
||||
binding = createBinding((IASTLabelStatement) parent);
|
||||
} else if (parent instanceof ICASTEnumerationSpecifier) {
|
||||
binding = createBinding((ICASTEnumerationSpecifier) parent);
|
||||
} else if (parent instanceof IASTEnumerator) {
|
||||
|
@ -529,33 +522,20 @@ public class CVisitor extends ASTQueries {
|
|||
return binding;
|
||||
}
|
||||
|
||||
private static IBinding createBinding(IASTStatement statement) {
|
||||
if (statement instanceof IASTGotoStatement) {
|
||||
char[] gotoName = ((IASTGotoStatement) statement).getName().toCharArray();
|
||||
IScope scope = getContainingScope(statement);
|
||||
if (scope != null && scope instanceof ICFunctionScope) {
|
||||
CFunctionScope functionScope = (CFunctionScope) scope;
|
||||
ILabel[] labels = functionScope.getLabels();
|
||||
for (ILabel label : labels) {
|
||||
if (CharArrayUtils.equals(label.getNameCharArray(), gotoName)) {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
//label not found
|
||||
return new ProblemBinding(((IASTGotoStatement) statement).getName(), IProblemBinding.SEMANTIC_LABEL_STATEMENT_NOT_FOUND, gotoName);
|
||||
}
|
||||
} else if (statement instanceof IASTLabelStatement) {
|
||||
IASTName name = ((IASTLabelStatement) statement).getName();
|
||||
IBinding binding = new CLabel(name);
|
||||
try {
|
||||
IScope scope = binding.getScope();
|
||||
if (scope instanceof ICFunctionScope)
|
||||
ASTInternal.addName(binding.getScope(), name);
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
return null;
|
||||
private static IBinding resolveBinding(IASTGotoStatement statement) {
|
||||
return resolveLabel(statement.getName());
|
||||
}
|
||||
|
||||
private static IBinding createBinding(IASTLabelStatement statement) {
|
||||
IASTName name = statement.getName();
|
||||
IBinding binding = new CLabel(name);
|
||||
try {
|
||||
IScope scope = binding.getScope();
|
||||
if (scope instanceof ICFunctionScope)
|
||||
ASTInternal.addName(binding.getScope(), name);
|
||||
} catch (DOMException e) {
|
||||
}
|
||||
return binding;
|
||||
}
|
||||
|
||||
private static IBinding createBinding(ICASTElaboratedTypeSpecifier elabTypeSpec) {
|
||||
|
@ -612,34 +592,6 @@ public class CVisitor extends ASTQueries {
|
|||
return null;
|
||||
}
|
||||
|
||||
private static IBinding createLabelReferenceBinding(IASTName name) {
|
||||
// Find function scope for r-value expression
|
||||
// void* labelPtr = &&foo;
|
||||
// foo: ^^^
|
||||
// return
|
||||
IBinding binding = null;
|
||||
IBinding enclosingFunction = findEnclosingFunction(name);
|
||||
if (enclosingFunction instanceof IFunction) {
|
||||
IFunction function = (IFunction) enclosingFunction;
|
||||
IScope functionScope = function.getFunctionScope();
|
||||
if (functionScope != null) {
|
||||
binding = functionScope.getBinding(name, false);
|
||||
if (!(binding instanceof ILabel)) {
|
||||
binding = new CLabel(name);
|
||||
ASTInternal.addName(functionScope, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (binding == null) {
|
||||
IASTNode parentExpression = name.getParent();
|
||||
binding = new ProblemBinding(parentExpression, IProblemBinding.SEMANTIC_BAD_SCOPE,
|
||||
parentExpression.getRawSignature().toCharArray());
|
||||
}
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
/**
|
||||
* if prefix == false, return an IBinding or null
|
||||
* if prefix == true, return an IBinding[] or null
|
||||
|
@ -878,6 +830,9 @@ public class CVisitor extends ASTQueries {
|
|||
IScope scope = getContainingScope(node);
|
||||
return lookup(scope, name);
|
||||
} else if (node instanceof IASTIdExpression) {
|
||||
if (isLabelReference(node)) {
|
||||
return resolveLabel(((IASTIdExpression) node).getName());
|
||||
}
|
||||
IScope scope = getContainingScope(node);
|
||||
IBinding binding = lookup(scope, ((IASTIdExpression) node).getName());
|
||||
if (binding instanceof IType && !(binding instanceof IProblemBinding) ) {
|
||||
|
@ -1653,8 +1608,10 @@ public class CVisitor extends ASTQueries {
|
|||
List<ILabel> b3 = new ArrayList<>();
|
||||
do {
|
||||
char[] n = name.toCharArray();
|
||||
if (scope instanceof ICFunctionScope) {
|
||||
ILabel[] labels = ((CFunctionScope) scope).getLabels();
|
||||
if (scope instanceof CFunctionScope) {
|
||||
IASTFunctionDefinition def = ASTQueries.findAncestorWithType(
|
||||
((CFunctionScope) scope).getPhysicalNode(), IASTFunctionDefinition.class);
|
||||
ILabel[] labels = getLabels(def);
|
||||
for (ILabel label : labels) {
|
||||
if (CharArrayUtils.equals(label.getNameCharArray(), n)) {
|
||||
b3.add(label);
|
||||
|
|
|
@ -294,16 +294,7 @@ public class CPPVisitor extends ASTQueries {
|
|||
return name.getBinding();
|
||||
}
|
||||
|
||||
// GNU Goto label reference
|
||||
//
|
||||
// void* labelPtr = &&foo; <-- label reference
|
||||
// foo:
|
||||
//
|
||||
boolean labelReference = isLabelReference(parent);
|
||||
|
||||
if (labelReference) {
|
||||
return createLabelReferenceBinding(name);
|
||||
} else if (parent instanceof IASTIdExpression) {
|
||||
if (parent instanceof IASTIdExpression) {
|
||||
return resolveBinding(parent);
|
||||
} else if (parent instanceof ICPPASTFieldReference) {
|
||||
return resolveBinding(parent);
|
||||
|
@ -320,7 +311,7 @@ public class CPPVisitor extends ASTQueries {
|
|||
} else if (parent instanceof IASTEnumerator) {
|
||||
return createBinding((IASTEnumerator) parent);
|
||||
} else if (parent instanceof IASTGotoStatement) {
|
||||
return createBinding((IASTGotoStatement) parent);
|
||||
return resolveBinding((IASTGotoStatement) parent);
|
||||
} else if (parent instanceof IASTLabelStatement) {
|
||||
return createBinding((IASTLabelStatement) parent);
|
||||
} else if (parent instanceof ICPPASTTemplateParameter) {
|
||||
|
@ -382,44 +373,8 @@ public class CPPVisitor extends ASTQueries {
|
|||
return scope == inScope;
|
||||
}
|
||||
|
||||
private static IBinding createLabelReferenceBinding(IASTName name) {
|
||||
// Find function scope for r-value expression
|
||||
// void* labelPtr = &&foo;
|
||||
// foo: ^^^
|
||||
// return
|
||||
IBinding binding = null;
|
||||
IBinding enclosingFunction = findEnclosingFunction(name);
|
||||
if (enclosingFunction instanceof IFunction) {
|
||||
IFunction function = (IFunction) enclosingFunction;
|
||||
IScope functionScope = function.getFunctionScope();
|
||||
if (functionScope != null) {
|
||||
binding = functionScope.getBinding(name, false);
|
||||
if (!(binding instanceof ILabel)) {
|
||||
binding = new CPPLabel(name);
|
||||
ASTInternal.addName(functionScope, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (binding == null) {
|
||||
IASTNode parentExpression = name.getParent();
|
||||
binding = new CPPScope.CPPScopeProblem(parentExpression, IProblemBinding.SEMANTIC_BAD_SCOPE,
|
||||
parentExpression.getRawSignature().toCharArray());
|
||||
}
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
private static IBinding createBinding(IASTGotoStatement gotoStatement) {
|
||||
IASTName name = gotoStatement.getName();
|
||||
ICPPFunctionScope functionScope = (ICPPFunctionScope) getContainingScope(name);
|
||||
IBinding binding = functionScope.getBinding(name, false);
|
||||
if (binding == null || !(binding instanceof ILabel)) {
|
||||
binding = new CPPLabel(name);
|
||||
ASTInternal.addName(functionScope, name);
|
||||
}
|
||||
|
||||
return binding;
|
||||
private static IBinding resolveBinding(IASTGotoStatement gotoStatement) {
|
||||
return resolveLabel(gotoStatement.getName());
|
||||
}
|
||||
|
||||
private static IBinding createBinding(IASTLabelStatement labelStatement) {
|
||||
|
@ -1423,6 +1378,9 @@ public class CPPVisitor extends ASTQueries {
|
|||
while (node != null) {
|
||||
if (node instanceof IASTIdExpression) {
|
||||
name = ((IASTIdExpression) node).getName();
|
||||
if (isLabelReference(node)) {
|
||||
return resolveLabel(name);
|
||||
}
|
||||
break;
|
||||
} else if (node instanceof ICPPASTFieldReference) {
|
||||
name = ((ICPPASTFieldReference) node).getFieldName();
|
||||
|
|
Loading…
Add table
Reference in a new issue