From c754042629931ec6579327c2a449efee842850ce Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Fri, 8 Feb 2008 13:51:56 +0000 Subject: [PATCH] Fixes name-resolution with using-directives, related to bug 26110. --- .../parser/tests/ast2/AST2CPPSpecTest.java | 22 +- .../core/parser/tests/ast2/AST2CPPTests.java | 2 +- .../parser/tests/ast2/AST2SpecBaseTest.java | 48 +++- .../eclipse/cdt/core/dom/ast/ASTTypeUtil.java | 17 +- .../core/dom/ast/cpp/ICPPNamespaceScope.java | 27 +- .../core/dom/ast/cpp/ICPPUsingDirective.java | 22 ++ .../core/dom/parser/c/GNUCSourceParser.java | 56 ++-- .../dom/parser/cpp/CPPASTTranslationUnit.java | 2 +- .../dom/parser/cpp/CPPNamespaceScope.java | 22 +- .../core/dom/parser/cpp/CPPSemantics.java | 258 +++++++++--------- .../dom/parser/cpp/CPPUsingDirective.java | 61 +++++ .../cpp/CompositeCPPNamespaceScope.java | 11 +- .../core/pdom/dom/cpp/PDOMCPPNamespace.java | 20 +- 13 files changed, 331 insertions(+), 237 deletions(-) create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPUsingDirective.java create mode 100644 core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUsingDirective.java diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java index cef6b11ad28..3acd1adf2eb 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPSpecTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 2008 IBM Corporation and others. * 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; @@ -727,7 +728,8 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { buffer.append("// S is { Y::h(int), Z::h(double) } and overload\n"); //$NON-NLS-1$ buffer.append("// resolution chooses Z::h(double)\n"); //$NON-NLS-1$ buffer.append("}\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, false, 0); + String[] problems= {"AB::x", "x", "AB::i", "i"}; + parse(buffer.toString(), ParserLanguage.CPP, problems); // qualified names are counted double, so 4 } /** @@ -2386,7 +2388,9 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { buffer.append("A::i++; // A::unique::i\n"); //$NON-NLS-1$ buffer.append("j++; // A::unique::j\n"); //$NON-NLS-1$ buffer.append("}\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, false, 0); + + String[] problems= {"i"}; + parse(buffer.toString(), ParserLanguage.CPP, problems); } /** @@ -2999,7 +3003,8 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { buffer.append("void f4() {\n"); //$NON-NLS-1$ buffer.append("i = 5; // illformed; neither i is visible\n"); //$NON-NLS-1$ buffer.append("}\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, false, 0); + String[] problems= {"i", "i"}; + parse(buffer.toString(), ParserLanguage.CPP, problems); } /** @@ -3032,7 +3037,8 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { buffer.append("using namespace N;\n"); //$NON-NLS-1$ buffer.append("i = 7; // error: both M::i and N::i are visible\n"); //$NON-NLS-1$ buffer.append("}\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, true, 0); + String[] problems= {"i"}; + parse(buffer.toString(), ParserLanguage.CPP, problems); } /** @@ -3081,7 +3087,8 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { buffer.append("int n = j; // D::j hides B::j\n"); //$NON-NLS-1$ buffer.append("}\n"); //$NON-NLS-1$ buffer.append("}\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, true, 0); + String[] problems= {"k"}; + parse(buffer.toString(), ParserLanguage.CPP, problems); } /** @@ -3140,7 +3147,8 @@ public class AST2CPPSpecTest extends AST2SpecBaseTest { buffer.append("f(1); //error: ambiguous: D::f(int) or E::f(int)?\n"); //$NON-NLS-1$ buffer.append("f('a'); //OK: D::f(char)\n"); //$NON-NLS-1$ buffer.append("}\n"); //$NON-NLS-1$ - parse(buffer.toString(), ParserLanguage.CPP, false, 0); + String[] problems= {"d1", "f"}; + parse(buffer.toString(), ParserLanguage.CPP, problems); } /** diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java index e40b800d5be..8e1c665a9d5 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2CPPTests.java @@ -3398,7 +3398,7 @@ public class AST2CPPTests extends AST2BaseTest { .getParent().getParent(); IScope scope = ((IASTCompoundStatement) def.getBody()).getScope(); IBinding[] bs = scope.find("f"); //$NON-NLS-1$ - assertEquals(bs.length, 3); + assertEquals(3, bs.length); assertSame(bs[0], f); assertSame(bs[1], f1); assertSame(bs[2], f2); diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2SpecBaseTest.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2SpecBaseTest.java index b04d449de58..72e9748e532 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2SpecBaseTest.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/core/parser/tests/ast2/AST2SpecBaseTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 2008 IBM Corporation and others. * 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 @@ -7,6 +7,7 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.core.parser.tests.ast2; @@ -64,20 +65,26 @@ public class AST2SpecBaseTest extends TestCase { * @throws ParserException */ protected void parseCandCPP( String code, boolean checkBindings, int expectedProblemBindings ) throws ParserException { - parse( code, ParserLanguage.C, false, true, checkBindings, expectedProblemBindings); - parse( code, ParserLanguage.CPP, false, true, checkBindings, expectedProblemBindings ); + parse( code, ParserLanguage.C, false, true, checkBindings, expectedProblemBindings, null); + parse( code, ParserLanguage.CPP, false, true, checkBindings, expectedProblemBindings, null ); } protected IASTTranslationUnit parse( String code, ParserLanguage lang, boolean checkBindings, int expectedProblemBindings ) throws ParserException { - return parse(code, lang, false, true, checkBindings, expectedProblemBindings ); + return parse(code, lang, false, true, checkBindings, expectedProblemBindings, null ); } + + protected IASTTranslationUnit parse(String code, ParserLanguage lang, String[] problems) throws ParserException { + return parse(code, lang, false, true, true, problems.length, problems ); + } + - private IASTTranslationUnit parse( String code, ParserLanguage lang, boolean useGNUExtensions, boolean expectNoProblems, boolean checkBindings, int expectedProblemBindings ) throws ParserException { + private IASTTranslationUnit parse( String code, ParserLanguage lang, boolean useGNUExtensions, boolean expectNoProblems, + boolean checkBindings, int expectedProblemBindings, String[] problems ) throws ParserException { // TODO beef this up with tests... i.e. run once with \n, and then run again with \r\n replacing \n ... etc // TODO another example might be to replace all characters with corresponding trigraph/digraph tests... CodeReader codeReader = new CodeReader(code.toCharArray()); - return parse(codeReader, lang, useGNUExtensions, expectNoProblems, checkBindings, expectedProblemBindings); + return parse(codeReader, lang, useGNUExtensions, expectNoProblems, checkBindings, expectedProblemBindings, problems); } // private IASTTranslationUnit parse( IFile filename, ParserLanguage lang, boolean useGNUExtensions, boolean expectNoProblems ) throws ParserException { @@ -93,7 +100,8 @@ public class AST2SpecBaseTest extends TestCase { // return parse(codeReader, lang, useGNUExtensions, expectNoProblems); // } - private IASTTranslationUnit parse(CodeReader codeReader, ParserLanguage lang, boolean useGNUExtensions, boolean expectNoProblems, boolean checkBindings, int expectedProblemBindings) throws ParserException { + private IASTTranslationUnit parse(CodeReader codeReader, ParserLanguage lang, boolean useGNUExtensions, + boolean expectNoProblems, boolean checkBindings, int expectedProblemBindings, String[] problems) throws ParserException { ScannerInfo scannerInfo = new ScannerInfo(); IScanner scanner= AST2BaseTest.createScanner(codeReader, lang, ParserMode.COMPLETE_PARSE, scannerInfo, false); @@ -129,13 +137,23 @@ public class AST2SpecBaseTest extends TestCase { if ( lang == ParserLanguage.CPP ) { CPPNameResolver res = new CPPNameResolver(); tu.accept( res ); - if (res.numProblemBindings != expectedProblemBindings ) - throw new ParserException("Expected " + expectedProblemBindings + " problems, encountered " + res.numProblemBindings ); //$NON-NLS-1$ //$NON-NLS-2$ + if (res.problemBindings.size() != expectedProblemBindings ) + throw new ParserException("Expected " + expectedProblemBindings + " problems, encountered " + res.problemBindings.size() ); //$NON-NLS-1$ //$NON-NLS-2$ + if (problems != null) { + for (int i = 0; i < problems.length; i++) { + assertEquals(problems[i], res.problemBindings.get(i)); + } + } } else if (lang == ParserLanguage.C ) { CNameResolver res = new CNameResolver(); tu.accept( res ); - if (res.numProblemBindings != expectedProblemBindings ) - throw new ParserException("Expected " + expectedProblemBindings + " problems, encountered " + res.numProblemBindings ); //$NON-NLS-1$ //$NON-NLS-2$ + if (res.problemBindings.size() != expectedProblemBindings ) + throw new ParserException("Expected " + expectedProblemBindings + " problems, encountered " + res.problemBindings.size() ); //$NON-NLS-1$ //$NON-NLS-2$ + if (problems != null) { + for (int i = 0; i < problems.length; i++) { + assertEquals(problems[i], res.problemBindings.get(i)); + } + } } } @@ -168,14 +186,14 @@ public class AST2SpecBaseTest extends TestCase { { shouldVisitNames = true; } - public int numProblemBindings=0; + public ArrayList problemBindings=new ArrayList(); public int numNullBindings=0; public List nameList = new ArrayList(); public int visit( IASTName name ){ nameList.add( name ); IBinding binding = name.resolveBinding(); if (binding instanceof IProblemBinding) - numProblemBindings++; + problemBindings.add(name.toString()); if (binding == null) numNullBindings++; return PROCESS_CONTINUE; @@ -192,14 +210,14 @@ public class AST2SpecBaseTest extends TestCase { { shouldVisitNames = true; } - public int numProblemBindings=0; + public ArrayList problemBindings=new ArrayList(); public int numNullBindings=0; public List nameList = new ArrayList(); public int visit( IASTName name ){ nameList.add( name ); IBinding binding = name.resolveBinding(); if (binding instanceof IProblemBinding) - numProblemBindings++; + problemBindings.add(name.toString()); if (binding == null) numNullBindings++; return PROCESS_CONTINUE; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java index 71f8733a58c..853685f35c6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/ASTTypeUtil.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 2008 IBM Corporation and others. * 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 @@ -9,7 +9,6 @@ * Rational Software - initial implementation * Markus Schorn (Wind River Systems) *******************************************************************************/ - package org.eclipse.cdt.core.dom.ast; import java.util.LinkedList; @@ -69,7 +68,7 @@ public class ASTTypeUtil { * @return the representation of the parameter type of an IFunctionType */ public static String getParameterTypeString(IFunctionType type) { - StringBuffer result = new StringBuffer(); + StringBuilder result = new StringBuilder(); String[] parms = getParameterTypeStringArray(type); result.append(Keywords.cpLPAREN); @@ -90,7 +89,7 @@ public class ASTTypeUtil { * @return representation of the type array as a comma-separated list */ public static String getTypeListString(IType[] types) { - StringBuffer result = new StringBuffer(); + StringBuilder result = new StringBuilder(); for(int i=0; i result= new LinkedList(); result.addFirst(getNameForAnonymous(binding)); ICPPScope scope = (ICPPScope) binding.getScope(); while( scope != null ){ @@ -530,7 +529,7 @@ public class ASTTypeUtil { } scope = (ICPPScope) scope.getParent(); } - return (String[]) result.toArray(new String[result.size()]); + return result.toArray(new String[result.size()]); } private static String getNameForAnonymous(IBinding binding) { @@ -570,7 +569,7 @@ public class ASTTypeUtil { if (loc != null) { char[] fname= loc.getFileName().toCharArray(); int fnamestart= findFileNameStart(fname); - StringBuffer buf= new StringBuffer(); + StringBuilder buf= new StringBuilder(); buf.append('{'); buf.append(fname, fnamestart, fname.length-fnamestart); buf.append(':'); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNamespaceScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNamespaceScope.java index 869735ae578..cf13df33ebf 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNamespaceScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPNamespaceScope.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2005 IBM Corporation and others. + * Copyright (c) 2004, 2008 IBM Corporation and others. * 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 @@ -7,36 +7,25 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ -/* - * Created on Nov 29, 2004 - */ package org.eclipse.cdt.core.dom.ast.cpp; import org.eclipse.cdt.core.dom.ast.DOMException; -import org.eclipse.cdt.core.dom.ast.IASTNode; /** - * @author aniefer + * A namespace scope is either a block-scope or a namespace-scope or global scope. */ public interface ICPPNamespaceScope extends ICPPScope { /** - * Add an IASTNode that nominates another namespace to this scope Most - * commonly, ICPPASTUsingDirectives, but in the case of unnamed namespaces, - * it could be an ICPPASTNamespaceDefinition - * - * @param directive + * Add a directive that nominates another namespace to this scope. */ - public void addUsingDirective(IASTNode directive) throws DOMException; + public void addUsingDirective(ICPPUsingDirective usingDirective) throws DOMException; /** - * Get the IASTNodes that have been added to this scope to nominate other - * namespaces during lookup. (ICPPASTUsingDirective or - * ICPPASTNamespaceDefinition) - * - * @return + * Get the using directives that have been added to this scope to nominate other + * namespaces during lookup. */ - public IASTNode[] getUsingDirectives() throws DOMException; - + public ICPPUsingDirective[] getUsingDirectives() throws DOMException; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPUsingDirective.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPUsingDirective.java new file mode 100644 index 00000000000..febcbbfe7fb --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/dom/ast/cpp/ICPPUsingDirective.java @@ -0,0 +1,22 @@ +package org.eclipse.cdt.core.dom.ast.cpp; + +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; + +/** + * Interface to model using directives + * @since 5.0 + */ +public interface ICPPUsingDirective { + + /** + * Returns the scope of the namespace that is nominated by this + * directive. + */ + ICPPNamespace getNamespace() throws DOMException; + + /** + * Returns the point of declaration as global offset ({@link ASTNode#getOffset()}). + */ + int getPointOfDeclaration(); +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java index b767e3aa6de..906e2d25d9c 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/c/GNUCSourceParser.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2007 IBM Corporation and others. + * Copyright (c) 2005, 2008 IBM Corporation and others. * 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 @@ -57,6 +57,7 @@ import org.eclipse.cdt.core.dom.ast.IASTLabelStatement; import org.eclipse.cdt.core.dom.ast.IASTLiteralExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNamedTypeSpecifier; +import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNullStatement; import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.IASTPointerOperator; @@ -158,7 +159,8 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { BacktrackException { if (LT(1) == IToken.tASSIGN) { consume(); - return cInitializerClause(Collections.EMPTY_LIST); + final List empty= Collections.emptyList(); + return cInitializerClause(empty); } return null; } @@ -167,7 +169,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { * @param scope * @return */ - protected IASTInitializer cInitializerClause(List designators) + protected IASTInitializer cInitializerClause(List designators) throws EndOfFileException, BacktrackException { IToken la = LA(1); int startingOffset = la.getOffset(); @@ -188,7 +190,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { int checkHashcode = LA(1).hashCode(); // required at least one initializer list // get designator list - List newDesignators = designatorList(); + List newDesignators = designatorList(); if (newDesignators.size() != 0) if (LT(1) == IToken.tASSIGN) consume(); @@ -269,10 +271,10 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { return new CASTInitializerExpression(); } - protected List designatorList() throws EndOfFileException, + protected List designatorList() throws EndOfFileException, BacktrackException { // designated initializers for C - List designatorList = Collections.EMPTY_LIST; + List designatorList= Collections.emptyList(); if (LT(1) == IToken.tDOT || LT(1) == IToken.tLBRACKET) { while (LT(1) == IToken.tDOT || LT(1) == IToken.tLBRACKET) { @@ -284,7 +286,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { IASTName n = createName(id); designator.setName(n); if (designatorList == Collections.EMPTY_LIST) - designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); + designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); designatorList.add(designator); } else if (LT(1) == IToken.tLBRACKET) { IToken mark = consume(); @@ -296,7 +298,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { ((ASTNode) designator).setOffsetAndLength(offset, lastOffset - offset); designator.setSubscriptExpression(constantExpression); if (designatorList == Collections.EMPTY_LIST) - designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); + designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); designatorList.add(designator); continue; } @@ -312,7 +314,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { designator.setRangeFloor(constantExpression1); designator.setRangeCeiling(constantExpression2); if (designatorList == Collections.EMPTY_LIST) - designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); + designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); designatorList.add(designator); } } else if (supportGCCStyleDesignators @@ -325,7 +327,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { IASTName n = createName(identifier); designator.setName(n); if (designatorList == Collections.EMPTY_LIST) - designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); + designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); designatorList.add(designator); } } @@ -346,7 +348,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { IASTName n = createName(identifier); designator.setName(n); if (designatorList == Collections.EMPTY_LIST) - designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); + designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); designatorList.add(designator); } else if (LT(1) == IToken.tLBRACKET) { int startOffset = consume().getOffset(); @@ -359,7 +361,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { designator.setRangeFloor(constantExpression1); designator.setRangeCeiling(constantExpression2); if (designatorList == Collections.EMPTY_LIST) - designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); + designatorList = new ArrayList(DEFAULT_DESIGNATOR_LIST_SIZE); designatorList.add(designator); } } @@ -884,7 +886,8 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { if (t != null) { consume(IToken.tRPAREN).getEndOffset(); if (LT(1) == IToken.tLBRACE) { - IASTInitializer i = cInitializerClause(Collections.EMPTY_LIST); + final List emptyList = Collections.emptyList(); + IASTInitializer i = cInitializerClause(emptyList); firstExpression = buildTypeIdInitializerExpression(t, i, offset, calculateEndOffset(i)); break; } @@ -1192,7 +1195,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { * @throws BacktrackException * request a backtrack */ - protected void consumePointerOperators(List pointerOps) + protected void consumePointerOperators(List pointerOps) throws EndOfFileException, BacktrackException { for (;;) { // __attribute__ in-between pointers @@ -1727,9 +1730,9 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { int startingOffset = la.getOffset(); int finalOffset = startingOffset; la = null; - List pointerOps = new ArrayList(DEFAULT_POINTEROPS_LIST_SIZE); - List parameters = Collections.EMPTY_LIST; - List arrayMods = Collections.EMPTY_LIST; + List pointerOps = new ArrayList(DEFAULT_POINTEROPS_LIST_SIZE); + List parameters = Collections.emptyList(); + List arrayMods = Collections.emptyList(); boolean encounteredVarArgs = false; IASTExpression bitField = null; boolean isFunction = false; @@ -1745,7 +1748,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); if (!pointerOps.isEmpty()) { - finalOffset = calculateEndOffset((IASTPointerOperator) pointerOps + finalOffset = calculateEndOffset(pointerOps .get(pointerOps.size() - 1)); } @@ -1773,10 +1776,10 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { // count the number of K&R C parameters (0 K&R C parameters // essentially means it's not K&R C) - if( !knr ) + if( !knr && supportKnRC) numKnRCParms = countKnRCParms(); - if (supportKnRC && numKnRCParms > 0) { // KnR C parameters were found so + if (numKnRCParms > 0) { // KnR C parameters were found so // handle the declarator accordingly parmNames = new IASTName[numKnRCParms]; parmDeclarations = new IASTDeclaration[numKnRCParms]; @@ -1878,7 +1881,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { IASTParameterDeclaration pd = parameterDeclaration(); finalOffset = calculateEndOffset(pd); if (parameters == Collections.EMPTY_LIST) - parameters = new ArrayList(DEFAULT_PARAMETERS_LIST_SIZE); + parameters = new ArrayList(DEFAULT_PARAMETERS_LIST_SIZE); parameters.add(pd); seenParameter = true; } @@ -1887,11 +1890,10 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { break; case IToken.tLBRACKET: if (arrayMods == Collections.EMPTY_LIST) - arrayMods = new ArrayList(DEFAULT_POINTEROPS_LIST_SIZE); + arrayMods = new ArrayList(DEFAULT_POINTEROPS_LIST_SIZE); consumeArrayModifiers(arrayMods); if (!arrayMods.isEmpty()) - finalOffset = calculateEndOffset((IASTArrayModifier) arrayMods - .get(arrayMods.size() - 1)); + finalOffset = calculateEndOffset(arrayMods.get(arrayMods.size() - 1)); continue; case IToken.tCOLON: consume(); @@ -1922,7 +1924,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { __attribute_decl_seq(supportAttributeSpecifiers, supportDeclspecSpecifiers); IASTDeclarator d = null; - if (numKnRCParms > 0) { + if (numKnRCParms > 0 && supportKnRC) { ICASTKnRFunctionDeclarator functionDecltor = createKnRFunctionDeclarator(); parmDeclarations = (IASTDeclaration[]) ArrayUtil.removeNulls( IASTDeclaration.class, parmDeclarations ); for (int i = 0; i < parmDeclarations.length; ++i) { @@ -1959,7 +1961,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { d = createDeclarator(); } for (int i = 0; i < pointerOps.size(); ++i) { - IASTPointerOperator po = (IASTPointerOperator) pointerOps.get(i); + IASTPointerOperator po = pointerOps.get(i); d.addPointerOperator(po); } if (innerDecl != null) { @@ -2021,7 +2023,7 @@ public class GNUCSourceParser extends AbstractGNUSourceCodeParser { return new CASTDeclarator(); } - protected void consumeArrayModifiers(List arrayMods) + protected void consumeArrayModifiers(List arrayMods) throws EndOfFileException, BacktrackException { while (LT(1) == IToken.tLBRACKET) { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java index 41d976295d2..de7ad22c899 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPASTTranslationUnit.java @@ -540,7 +540,7 @@ public class CPPASTTranslationUnit extends CPPASTNode implements ICPPASTTranslat if (scope instanceof ICPPNamespaceScope) { IScope result= fMappedScopes.get(scope); if (result == null) { - result= getScope().findNamespaecScope(scope); + result= getScope().findNamespaceScope(scope); if (result == null) { result= scope; } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNamespaceScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNamespaceScope.java index f398ef9c90a..04f325ec8b4 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNamespaceScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPNamespaceScope.java @@ -9,12 +9,10 @@ * IBM Corporation - initial API and implementation * Markus Schorn (Wind River Systems) *******************************************************************************/ -/* - * Created on Nov 29, 2004 - */ package org.eclipse.cdt.internal.core.dom.parser.cpp; import org.eclipse.cdt.core.dom.IName; +import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IScope; @@ -22,14 +20,16 @@ import org.eclipse.cdt.core.dom.ast.cpp.CPPASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTLinkageSpecification; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.parser.util.ArrayUtil; +import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPSemantics.LookupData; import org.eclipse.cdt.internal.core.index.IIndexScope; /** * @author aniefer */ public class CPPNamespaceScope extends CPPScope implements ICPPNamespaceScope{ - IASTNode[] usings = null; + ICPPUsingDirective[] usings = null; public CPPNamespaceScope( IASTNode physicalNode ) { super( physicalNode ); @@ -38,14 +38,18 @@ public class CPPNamespaceScope extends CPPScope implements ICPPNamespaceScope{ /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope#getUsingDirectives() */ - public IASTNode[] getUsingDirectives() { - return (IASTNode[]) ArrayUtil.trim( IASTNode.class, usings, true ); + public ICPPUsingDirective[] getUsingDirectives() throws DOMException { + if (!isFullyCached()) { + LookupData ld= new LookupData(); + CPPSemantics.lookupInScope(ld, this, null); + } + return (ICPPUsingDirective[]) ArrayUtil.trim( ICPPUsingDirective.class, usings, true ); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope#addUsingDirective(org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective) */ - public void addUsingDirective(IASTNode directive) { - usings = (IASTNode[]) ArrayUtil.append( IASTNode.class, usings, directive ); + public void addUsingDirective(ICPPUsingDirective directive) { + usings = (ICPPUsingDirective[]) ArrayUtil.append( ICPPUsingDirective.class, usings, directive ); } /* (non-Javadoc) @@ -59,7 +63,7 @@ public class CPPNamespaceScope extends CPPScope implements ICPPNamespaceScope{ return null; } - public IScope findNamespaecScope(IIndexScope scope) { + public IScope findNamespaceScope(IIndexScope scope) { final String[] qname= scope.getScopeBinding().getQualifiedName(); final IScope[] result= {null}; final CPPASTVisitor visitor= new CPPASTVisitor () { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java index 83d15c99eb7..879b8aba254 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPSemantics.java @@ -13,6 +13,14 @@ *******************************************************************************/ package org.eclipse.cdt.internal.core.dom.parser.cpp; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; @@ -90,6 +98,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTWhileStatement; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBase; import org.eclipse.cdt.core.dom.ast.cpp.ICPPBasicType; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPBlockScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; @@ -100,7 +109,6 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMember; import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod; -import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPPointerToMemberType; @@ -115,15 +123,14 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateTypeParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.ArrayUtil; import org.eclipse.cdt.core.parser.util.CharArrayObjectMap; import org.eclipse.cdt.core.parser.util.CharArrayUtils; -import org.eclipse.cdt.core.parser.util.ObjectMap; import org.eclipse.cdt.core.parser.util.ObjectSet; -import org.eclipse.cdt.core.parser.util.ArrayUtil.ArrayWrapper; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.ITypeContainer; @@ -144,8 +151,9 @@ public class CPPSemantics { static protected class LookupData { protected IASTName astName; - public ObjectMap usingDirectives = ObjectMap.EMPTY_MAP; - public ObjectSet visited = ObjectSet.EMPTY_SET; //used to ensure we don't visit things more than once + protected CPPASTTranslationUnit tu; + public Map> usingDirectives= Collections.emptyMap(); + public ObjectSet visited= new ObjectSet(1); //used to ensure we don't visit things more than once public ObjectSet inheritanceChain; //used to detect circular inheritance public ObjectSet associated = ObjectSet.EMPTY_SET; @@ -167,6 +175,7 @@ public class CPPSemantics { public LookupData( IASTName n ){ astName = n; + tu= (CPPASTTranslationUnit) astName.getTranslationUnit(); typesOnly = typesOnly(); considerConstructors = considerConstructors(); checkWholeClassScope = checkWholeClassScope(); @@ -292,7 +301,8 @@ public class CPPSemantics { if( astName.getPropertyInParent() == STRING_LOOKUP_PROPERTY ) return false; IASTNode p1 = astName.getParent(); if( p1 instanceof ICPPASTQualifiedName ){ - return ((ICPPASTQualifiedName)p1).getNames()[0] != astName; + final IASTName[] qnames = ((ICPPASTQualifiedName)p1).getNames(); + return qnames.length == 1 || qnames[0] != astName; } return p1 instanceof ICPPASTFieldReference; } @@ -858,7 +868,7 @@ public class CPPSemantics { IType p = ps[i]; p = getUltimateType( p, true ); try { - getAssociatedScopes( p, namespaces, classes, (CPPASTTranslationUnit) data.astName.getTranslationUnit()); + getAssociatedScopes( p, namespaces, classes, data.tu); } catch ( DOMException e ) { } } @@ -1011,9 +1021,8 @@ public class CPPSemantics { IIndexFileSet fileSet= IIndexFileSet.EMPTY; if (node != null) { - final IASTTranslationUnit tu= node.getTranslationUnit(); - if (tu != null) { - final IIndexFileSet fs= (IIndexFileSet) tu.getAdapter(IIndexFileSet.class); + if (data.tu != null) { + final IIndexFileSet fs= (IIndexFileSet) data.tu.getAdapter(IIndexFileSet.class); if (fs != null) { fileSet= fs; } @@ -1040,7 +1049,6 @@ public class CPPSemantics { while( scope != null ){ IASTNode blockItem = CPPVisitor.getContainingBlockItem( node ); - ArrayWrapper directives = null; if( !data.usingDirectivesOnly ){ if( ASTInternal.isFullyCached(scope) ){ if (!data.contentAssist && data.astName != null) { @@ -1089,36 +1097,29 @@ public class CPPSemantics { } } - if( (!data.hasResults() || data.contentAssist) && scope instanceof ICPPNamespaceScope ){ - directives = new ArrayWrapper(); - directives.array = ((ICPPNamespaceScope) scope).getUsingDirectives(); - if( directives.array != null ){ - for( int i = 0; i < directives.array.length; i++ ){ - if( !CPPSemantics.declaredBefore( directives.array[i], blockItem ) ){ - directives.array[i] = null; - directives.array = ArrayUtil.trim( IASTNode.class, directives.array ); + // store using-directives found in this block or namespace for later use. + if( (!data.hasResults() || !data.qualified() || data.contentAssist) && scope instanceof ICPPNamespaceScope ){ + final ICPPNamespaceScope blockScope= (ICPPNamespaceScope) scope; + if (! (blockScope instanceof ICPPBlockScope)) { + data.visited.put(blockScope); // namespace has been searched. + } + ICPPUsingDirective[] uds= blockScope.getUsingDirectives(); + if( uds != null && uds.length > 0) { + HashSet handled= new HashSet(); + for( int i = 0; i < uds.length; i++ ){ + final ICPPUsingDirective ud = uds[i]; + if( CPPSemantics.declaredBefore( ud, blockItem ) ){ + storeUsingDirective(data, blockScope, ud, handled); } } } } } - - if( !data.ignoreUsingDirectives ) { - data.visited.clear(); - if( data.contentAssist || !data.hasResults() ){ - Object[] transitives = lookupInNominated( data, scope, null ); - - processDirectives( data, scope, transitives ); - if( directives != null && directives.array != null && directives.array.length != 0 ) - processDirectives( data, scope, directives.array ); - - while( !data.usingDirectives.isEmpty() && data.usingDirectives.get( scope ) != null ){ - transitives = lookupInNominated( data, scope, transitives ); - - if( !data.qualified() || ( data.contentAssist || !data.hasResults()) ){ - processDirectives( data, scope, transitives ); - } - } + + // lookup in nominated namespaces + if( !data.ignoreUsingDirectives && scope instanceof ICPPNamespaceScope && !(scope instanceof ICPPBlockScope)) { + if( !data.hasResults() || !data.qualified() || data.contentAssist) { + lookupInNominated(data, (ICPPNamespaceScope) scope); } } @@ -1146,7 +1147,7 @@ public class CPPSemantics { if( blockItem != null ) node = blockItem; - ICPPScope parentScope = (ICPPScope) getParentScope(scope, (CPPASTTranslationUnit) node.getTranslationUnit()); + ICPPScope parentScope = (ICPPScope) getParentScope(scope, data.tu); if( parentScope instanceof ICPPTemplateScope ){ IASTNode parent = node.getParent(); while( parent != null && !(parent instanceof ICPPASTTemplateDeclaration) ){ @@ -1221,8 +1222,6 @@ public class CPPSemantics { if( !bases[i].isVirtual() || !data.visited.containsKey( parent ) ){ if( bases[i].isVirtual() ){ - if( data.visited == ObjectSet.EMPTY_SET ) - data.visited = new ObjectSet(2); data.visited.put( parent ); } @@ -1313,8 +1312,6 @@ public class CPPSemantics { if (b instanceof ICPPClassType) { IScope bScope = ((ICPPClassType)b).getCompositeScope(); if( bases[i].isVirtual() ){ - if( data.visited == ObjectSet.EMPTY_SET ) - data.visited = new ObjectSet(2); if (bScope != null) data.visited.put(bScope); } else if ( bScope != null ) { @@ -1385,53 +1382,55 @@ public class CPPSemantics { return false; } - static private void processDirectives( CPPSemantics.LookupData data, IScope scope, Object[] directives ) throws DOMException{ - if( directives == null || directives.length == 0 ) + /** + * Stores the using directive with the scope where the members of the nominated namespace will appear. + * In case of an unqualified lookup the transitive directives are stored, also. This is important because + * the members nominated by a transitive directive can appear before those of the original directive. + */ + static private void storeUsingDirective(CPPSemantics.LookupData data, ICPPNamespaceScope container, + ICPPUsingDirective directive, Set handled) throws DOMException { + final ICPPNamespaceScope nominated= directive.getNamespace().getNamespaceScope(); + if (nominated == null || data.visited.containsKey(nominated) || (handled != null && !handled.add(nominated))) { return; - - ICPPScope enclosing = null; - IScope temp = null; - - int size = directives.length; - for( int i = 0; i < size && directives[i] != null; i++ ){ - Object d = directives[i]; - IBinding binding = null; - if( d instanceof ICPPASTUsingDirective ){ - binding = ((ICPPASTUsingDirective)d).getQualifiedName().resolveBinding(); - } else if( d instanceof ICPPASTNamespaceDefinition ){ - binding = ((ICPPASTNamespaceDefinition)d).getName().resolveBinding(); - } - if( binding instanceof ICPPNamespace ){ - temp = ((ICPPNamespace)binding).getNamespaceScope(); - } else - continue; - - //namespace are searched at most once - if( !data.visited.containsKey( temp ) ){ - enclosing = getClosestEnclosingScope( scope, temp, (CPPASTTranslationUnit) data.astName.getTranslationUnit()); - - //data.usingDirectives is a map from enclosing scope to a IScope[] - //of namespaces to consider when we reach that enclosing scope - IScope [] scopes = (IScope[]) ( data.usingDirectives.isEmpty() ? null : data.usingDirectives.get( enclosing ) ); - scopes = (IScope[]) ArrayUtil.append( IScope.class, scopes, temp ); - if( data.usingDirectives == ObjectMap.EMPTY_MAP ){ - data.usingDirectives = new ObjectMap(2); + } + // 7.3.4.1 names appear at end of common enclosing scope of container and nominated scope. + final IScope appearsIn= getCommonEnclosingScope(nominated, container, data.tu); + if (appearsIn instanceof ICPPNamespaceScope) { + // store the directive with the scope where it has to be considered + List listOfNominated= data.usingDirectives.get(appearsIn); + if (listOfNominated == null) { + listOfNominated= new ArrayList(1); + if (data.usingDirectives.isEmpty()) { + data.usingDirectives= new HashMap>(); } - data.usingDirectives.put( enclosing, scopes ); + data.usingDirectives.put((ICPPNamespaceScope) appearsIn, listOfNominated); } + listOfNominated.add(nominated); } + // in a non-qualified lookup the transitive directive have to be stored right away, they may overtake the + // container. + if (!data.qualified() || data.contentAssist) { + assert handled != null; + ICPPUsingDirective[] transitive= nominated.getUsingDirectives(); + for (int i = 0; i < transitive.length; i++) { + storeUsingDirective(data, container, transitive[i], handled); + } + } } - static private ICPPScope getClosestEnclosingScope( IScope scope1, IScope scope2, CPPASTTranslationUnit tu) throws DOMException{ + /** + * Computes the common enclosing scope of s1 and s2. + */ + static private ICPPScope getCommonEnclosingScope(IScope s1, IScope s2, CPPASTTranslationUnit tu) throws DOMException { ObjectSet set = new ObjectSet( 2 ); - IScope parent = scope1; + IScope parent= s1; while( parent != null ){ set.put( parent ); - parent = getParentScope(parent, tu); + parent= getParentScope(parent, tu); } - parent = scope2; - while( parent != null && !set.containsKey( parent ) ){ + parent= s2; + while(parent != null && !set.containsKey( parent ) ){ parent = getParentScope(parent, tu); } return (ICPPScope) parent; @@ -1520,12 +1519,19 @@ public class CPPSemantics { if( item instanceof IASTDeclarationStatement ) item = ((IASTDeclarationStatement)item).getDeclaration(); - if( item instanceof ICPPASTUsingDirective || - (item instanceof ICPPASTNamespaceDefinition && - ((ICPPASTNamespaceDefinition)item).getName().toCharArray().length == 0) ) - { - if( scope instanceof ICPPNamespaceScope ) - ((ICPPNamespaceScope)scope).addUsingDirective( item ); + if( item instanceof ICPPASTUsingDirective ) { + if( scope instanceof ICPPNamespaceScope ) { + final ICPPNamespaceScope nsscope = (ICPPNamespaceScope)scope; + final ICPPASTUsingDirective usingDirective = (ICPPASTUsingDirective) item; + nsscope.addUsingDirective(new CPPUsingDirective(usingDirective)); + } + } else if (item instanceof ICPPASTNamespaceDefinition && + ((ICPPASTNamespaceDefinition)item).getName().toCharArray().length == 0) { + if( scope instanceof ICPPNamespaceScope ) { + final ICPPNamespaceScope nsscope = (ICPPNamespaceScope)scope; + final ICPPASTNamespaceDefinition nsdef= (ICPPASTNamespaceDefinition) item; + nsscope.addUsingDirective(new CPPUsingDirective(nsdef)); + } } else { //possible is IASTName or IASTName[] possible = collectResult( data, scope, item, (item == parent) ); @@ -1612,63 +1618,49 @@ public class CPPSemantics { return found; } - static private Object[] lookupInNominated( CPPSemantics.LookupData data, ICPPScope scope, Object[] transitives ) throws DOMException{ - if( data.usingDirectives.isEmpty() ) - return transitives; - - ICPPScope temp = null; - - IScope [] directives = (IScope[]) data.usingDirectives.remove( scope ); - if( directives == null || directives.length == 0 ) { - return transitives; - } - for( int i = 0; i < directives.length && directives[i] != null; i++ ){ - temp = (ICPPScope) directives[i]; - if( !data.visited.containsKey( temp ) ){ - if( data.visited == ObjectSet.EMPTY_SET ) { - data.visited = new ObjectSet(2); + /** + * Perform lookup in nominated namespaces that appear in the given scope. For unqualified lookups the method assumes + * that transitive directives have been stored in the lookup-data. For qualified lookups the transitive directives + * are considered if the lookup of the original directive returns empty. + */ + static private void lookupInNominated(CPPSemantics.LookupData data, ICPPNamespaceScope scope) throws DOMException{ + List allNominated= data.usingDirectives.remove(scope); + while (allNominated != null) { + for (ICPPNamespaceScope nominated : allNominated) { + if (data.visited.containsKey(nominated)) { + continue; } - data.visited.put( temp ); - ArrayWrapper usings = new ArrayWrapper(); - + data.visited.put(nominated); + boolean found = false; - if( ASTInternal.isFullyCached(temp) ) { - if ( !data.contentAssist ){ - IBinding binding = temp.getBinding( data.astName, true ); - if( binding != null && - ( CPPSemantics.declaredBefore( binding, data.astName ) || - (scope instanceof ICPPClassScope && data.checkWholeClassScope) ) ) - { - mergeResults( data, binding, true ); - found = true; - } - } else { - IBinding[] bindings = temp.getBindings( data.astName, true, data.prefixLookup ); - if (bindings != null && bindings.length > 0) { - mergeResults( data, bindings, true ); - found = true; - } + if (ASTInternal.isFullyCached(nominated)) { + IBinding[] bindings= nominated.getBindings(data.astName, true, data.prefixLookup); + if (bindings != null && bindings.length > 0) { + mergeResults( data, bindings, true ); + found = true; } } else { - IASTName [] f = lookupInScope( data, temp, null ); + IASTName [] f = lookupInScope( data, nominated, null ); if( f != null ) { mergeResults( data, f, true ); found = true; } } - if( !found && temp instanceof ICPPNamespaceScope ){ - usings.array = ((ICPPNamespaceScope) temp).getUsingDirectives(); - } - - //only consider the transitive using directives if we are an unqualified - //lookup, or we didn't find the name in decl - if( usings.array != null && usings.array.length > 0 && (!data.qualified() || !found ) ){ - transitives = ArrayUtil.addAll( Object.class, transitives, usings.array ); + // in the qualified lookup we have to nominate the transitive directives only when + // the lookup did not succeed. In the qualified case this is done earlier, when the directive + // is encountered. + if (!found && data.qualified() && !data.contentAssist) { + ICPPUsingDirective[] usings= nominated.getUsingDirectives(); + for (int i = 0; i < usings.length; i++) { + ICPPUsingDirective using = usings[i]; + storeUsingDirective(data, scope, using, null); + } } } + // retry with transitive directives that may have been nominated in a qualified lookup + allNominated= data.usingDirectives.remove(scope); } - return transitives; } static private Object collectResult( CPPSemantics.LookupData data, ICPPScope scope, IASTNode node, boolean checkAux ) throws DOMException{ @@ -1924,12 +1916,14 @@ public class CPPSemantics { static public boolean declaredBefore( Object obj, IASTNode node ){ if( node == null ) return true; if( node.getPropertyInParent() == STRING_LOOKUP_PROPERTY ) return true; + final int pointOfRef= ((ASTNode) node).getOffset(); ASTNode nd = null; if( obj instanceof ICPPSpecialization ){ obj = ((ICPPSpecialization)obj).getSpecializedBinding(); } + int pointOfDecl= -1; if( obj instanceof ICPPInternalBinding ){ ICPPInternalBinding cpp = (ICPPInternalBinding) obj; IASTNode[] n = cpp.getDeclarations(); @@ -1945,10 +1939,11 @@ public class CPPSemantics { return true; } else if( obj instanceof ASTNode ){ nd = (ASTNode) obj; + } else if( obj instanceof ICPPUsingDirective) { + pointOfDecl= ((ICPPUsingDirective) obj).getPointOfDeclaration(); } - if( nd != null ){ - int pointOfDecl = 0; + if( pointOfDecl < 0 && nd != null ){ ASTNodeProperty prop = nd.getPropertyInParent(); //point of declaration for a name is immediately after its complete declarator and before its initializer if( prop == IASTDeclarator.DECLARATOR_NAME || nd instanceof IASTDeclarator ){ @@ -1978,11 +1973,8 @@ public class CPPSemantics { pointOfDecl = nd.getOffset() + nd.getLength(); } else pointOfDecl = nd.getOffset() + nd.getLength(); - - return ( pointOfDecl < ((ASTNode)node).getOffset() ); - } - return true; // TODO - I changed this to true + return ( pointOfDecl < pointOfRef ); } static private IBinding resolveAmbiguities( CPPSemantics.LookupData data, IASTName name ) throws DOMException { diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUsingDirective.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUsingDirective.java new file mode 100644 index 00000000000..7c41abe9df9 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPUsingDirective.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2008 Wind River Systems, Inc. and others. + * 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 + * + * Contributors: + * Markus Schorn - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser.cpp; + +import org.eclipse.cdt.core.dom.ast.DOMException; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IBinding; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamespaceDefinition; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; +import org.eclipse.cdt.internal.core.dom.parser.ASTNode; + +/** + * Represents a using-directive found in the AST. + */ +public class CPPUsingDirective implements ICPPUsingDirective { + + private IASTName fNamespaceName; + + /** + * Constructor for explicit using directives + */ + public CPPUsingDirective(ICPPASTUsingDirective node) { + fNamespaceName= node.getQualifiedName(); + } + + /** + * Constructor for unnamed namespaces introducing an implicit using directive. + */ + public CPPUsingDirective(ICPPASTNamespaceDefinition nsdef) { + fNamespaceName= nsdef.getName(); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective#getNamespaceScope() + */ + public ICPPNamespace getNamespace() throws DOMException { + IBinding binding= fNamespaceName.resolveBinding(); + if (binding instanceof ICPPNamespace) { + return (ICPPNamespace) binding; + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective#getPointOfDeclaration() + */ + public int getPointOfDeclaration() { + final ASTNode astNode = (ASTNode) fNamespaceName; + return astNode.getOffset() + astNode.getLength(); + } +} diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPNamespaceScope.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPNamespaceScope.java index 3441182570d..702e8455a64 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPNamespaceScope.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/index/composite/cpp/CompositeCPPNamespaceScope.java @@ -6,18 +6,19 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * Andrew Ferguson (Symbian) - Initial implementation + * Andrew Ferguson (Symbian) - Initial implementation + * Markus Schorn (Wind River Systems) *******************************************************************************/ package org.eclipse.cdt.internal.core.index.composite.cpp; import org.eclipse.cdt.core.dom.IName; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.parser.util.ArrayUtil; @@ -33,12 +34,12 @@ class CompositeCPPNamespaceScope extends CompositeScope implements ICPPNamespace this.namespaces = namespaces; } - public void addUsingDirective(IASTNode directive) throws DOMException { + public void addUsingDirective(ICPPUsingDirective directive) throws DOMException { fail(); } - public IASTNode[] getUsingDirectives() throws DOMException { - return new IASTNode[0]; // same behaviour as PDOMCPPNamespace + public ICPPUsingDirective[] getUsingDirectives() throws DOMException { + return new ICPPUsingDirective[0]; // same behavior as PDOMCPPNamespace } public IBinding getBinding(IASTName name, boolean resolve, IIndexFileSet fileSet) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java index eb00dedbdfd..52b95eb6e88 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/cpp/PDOMCPPNamespace.java @@ -6,12 +6,11 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * QNX - Initial API and implementation - * Markus Schorn (Wind River Systems) - * Andrew Ferguson (Symbian) - * Bryan Wilkinson (QNX) + * QNX - Initial API and implementation + * Markus Schorn (Wind River Systems) + * Andrew Ferguson (Symbian) + * Bryan Wilkinson (QNX) *******************************************************************************/ - package org.eclipse.cdt.internal.core.pdom.dom.cpp; import java.util.ArrayList; @@ -21,12 +20,12 @@ import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.dom.IPDOMVisitor; import org.eclipse.cdt.core.dom.ast.DOMException; import org.eclipse.cdt.core.dom.ast.IASTName; -import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.cpp.ICPPDelegate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace; import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceScope; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDirective; import org.eclipse.cdt.core.index.IIndexBinding; import org.eclipse.cdt.core.index.IIndexFileSet; import org.eclipse.cdt.core.index.IndexFilter; @@ -106,9 +105,8 @@ class PDOMCPPNamespace extends PDOMCPPBinding return this; } - public IASTNode[] getUsingDirectives() throws DOMException { - // TODO - return new IASTNode[0]; + public ICPPUsingDirective[] getUsingDirectives() throws DOMException { + return new ICPPUsingDirective[0]; } public IBinding[] find(String name) { @@ -160,7 +158,7 @@ class PDOMCPPNamespace extends PDOMCPPBinding if (result != null) { return result; } - BindingCollector visitor = new BindingCollector(getLinkageImpl(), name, null, false, true); + BindingCollector visitor = new BindingCollector(getLinkageImpl(), name, IndexFilter.ALL_DECLARED_OR_IMPLICIT, false, true); getIndex().accept(visitor); result = visitor.getBindings(); pdom.putCachedResult(key, result); @@ -195,7 +193,7 @@ class PDOMCPPNamespace extends PDOMCPPBinding return result; } - public void addUsingDirective(IASTNode directive) throws DOMException {fail();} + public void addUsingDirective(ICPPUsingDirective directive) throws DOMException {fail();} public IIndexBinding getScopeBinding() { return this;