1
0
Fork 0
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:
Nathan Ridge 2016-01-07 16:24:07 -05:00 committed by Sergey Prigogin
parent 1b0fe3a41e
commit ea73b8149c
7 changed files with 139 additions and 172 deletions

View file

@ -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));
}
}

View file

@ -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

View file

@ -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 = {};
/**

View file

@ -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);
}
}

View file

@ -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;
}
}
}

View file

@ -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);

View file

@ -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();