diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java index 2a7a50676ec..600103dbecf 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2Tests.java @@ -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)); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTLabelStatement.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTLabelStatement.java index 6a00001b543..60ace45ca60 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTLabelStatement.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/IASTLabelStatement.java @@ -17,9 +17,15 @@ 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$ public static final ASTNodeProperty NESTED_STATEMENT = new ASTNodeProperty("IASTLabelStatement.NESTED_STATEMENT - statement 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 diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ILabel.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ILabel.java index 7e1367a7495..1164a2ac990 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ILabel.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ILabel.java @@ -18,9 +18,15 @@ 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 = {}; - + /** * Returns the label statement for this label. */ diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTQueries.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTQueries.java index 7e67c018a85..d8fa2b94850 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTQueries.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTQueries.java @@ -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 findAncestorWithType(IASTNode node, Class 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 null. */ 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); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CFunctionScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CFunctionScope.java index 46ab76820de..cc66bbb92f8 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CFunctionScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CFunctionScope.java @@ -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; - } - } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java index f0faa4c6d37..5ca547d2ddb 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/CVisitor.java @@ -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 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); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java index 5b540c94fb0..c41cc565630 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPVisitor.java @@ -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();