From c5d05dd874b1700f6eb849510a78992f50197733 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Fri, 13 Nov 2009 10:23:27 +0000 Subject: [PATCH] Consider all declarations of a variable for determining its type, bug 294144. --- .../core/parser/tests/ast2/AST2CPPTests.java | 14 +++ .../core/dom/parser/cpp/CPPVariable.java | 112 ++++++++++++------ .../parser/cpp/semantics/CPPSemantics.java | 23 +++- .../dom/parser/cpp/semantics/CPPVisitor.java | 8 ++ 4 files changed, 119 insertions(+), 38 deletions(-) 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 2d34c5bf385..2ad9404f608 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 @@ -7699,5 +7699,19 @@ public class AST2CPPTests extends AST2BaseTest { final String code = getAboveComment(); parseAndCheckBindings(code, ParserLanguage.CPP); } + + // template char (&func(T (&array)[N]))[N]; + // struct A { + // static int array[]; + // }; + // int A::array[] = { 0 }; + // + // void test() { + // func(A::array); // func is not resolved + // } + public void testCompleteArrayTypeWithIncompleteDeclaration_294144() throws Exception { + final String code = getAboveComment(); + parseAndCheckBindings(code, ParserLanguage.CPP); + } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java index d60155ca9ba..157a94eb970 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPVariable.java @@ -23,6 +23,8 @@ import org.eclipse.cdt.core.dom.ast.IASTInitializerExpression; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; +import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; +import org.eclipse.cdt.core.dom.ast.IArrayType; import org.eclipse.cdt.core.dom.ast.IBasicType; import org.eclipse.cdt.core.dom.ast.IBinding; import org.eclipse.cdt.core.dom.ast.IPointerType; @@ -88,9 +90,10 @@ public class CPPVariable extends PlatformObject implements ICPPVariable, ICPPInt } } - private IASTName declarations[] = null; - private IASTName definition = null; - private IType type = null; + private IASTName fDefinition = null; + private IASTName fDeclarations[] = null; + private IType fType = null; + private boolean fAllResolved; public CPPVariable(IASTName name) { boolean isDef = name == null ? false : name.isDefinition(); @@ -100,9 +103,9 @@ public class CPPVariable extends PlatformObject implements ICPPVariable, ICPPInt } if (isDef) - definition = name; + fDefinition = name; else - declarations = new IASTName[] { name }; + fDeclarations = new IASTName[] { name }; // built-in variables supply a null if (name != null) { @@ -131,54 +134,91 @@ public class CPPVariable extends PlatformObject implements ICPPVariable, ICPPInt if (!(node instanceof IASTName)) return; IASTName name = (IASTName) node; - if (name.isDefinition()) { - definition = name; - } else if (declarations == null) { - declarations = new IASTName[] { name }; - } else { - //keep the lowest offset declaration in[0] - if (declarations.length > 0 && ((ASTNode) node).getOffset() < ((ASTNode) declarations[0]).getOffset()) { - declarations = (IASTName[]) ArrayUtil.prepend(IASTName.class, declarations, name); + if (fDefinition == null && name.isDefinition()) { + fDefinition = name; + } else if (fDeclarations == null) { + fDeclarations = new IASTName[] { name }; + } else { + // keep the lowest offset declaration at the first position + if (fDeclarations.length > 0 + && ((ASTNode) node).getOffset() < ((ASTNode) fDeclarations[0]).getOffset()) { + fDeclarations = (IASTName[]) ArrayUtil.prepend(IASTName.class, fDeclarations, name); } else { - declarations = (IASTName[]) ArrayUtil.append(IASTName.class, declarations, name); + fDeclarations = (IASTName[]) ArrayUtil.append(IASTName.class, fDeclarations, name); } - } + } + // array types may be incomplete + if (fType instanceof IArrayType) { + fType = null; + } } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPBinding#getDeclarations() */ public IASTNode[] getDeclarations() { - return declarations; + return fDeclarations; } /* (non-Javadoc) * @see org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPBinding#getDefinition() */ public IASTNode getDefinition() { - return definition; + return fDefinition; } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IVariable#getType() */ public IType getType() { - if (type == null) { - IASTName n = null; - if (definition != null) - n = definition; - else if (declarations != null && declarations.length > 0) - n = declarations[0]; - + if (fType != null) { + return fType; + } + + IArrayType firstCandidate= null; + final int length = fDeclarations == null ? 0 : fDeclarations.length; + for (int i = -1; i < length; i++) { + IASTName n = i==-1 ? fDefinition : fDeclarations[i]; if (n != null) { while (n.getParent() instanceof IASTName) n = (IASTName) n.getParent(); + IASTNode node = n.getParent(); - if (node instanceof IASTDeclarator) - type = CPPVisitor.createType((IASTDeclarator) node); + if (node instanceof IASTDeclarator) { + IType t= CPPVisitor.createType((IASTDeclarator) node); + if (t instanceof IArrayType && ((IArrayType) t).getSize() == null) { + if (firstCandidate == null) { + firstCandidate= (IArrayType) t; + } + } else { + return fType= t; + } + } } } - return type; + fType= firstCandidate; + if (!fAllResolved) { + resolveAllDeclarations(); + return getType(); + } + return fType; + } + + private void resolveAllDeclarations() { + if (fAllResolved) + return; + fAllResolved= true; + final int length = fDeclarations == null ? 0 : fDeclarations.length; + for (int i = -1; i < length; i++) { + IASTName n = i==-1 ? fDefinition : fDeclarations[i]; + if (n != null) { + IASTTranslationUnit tu = n.getTranslationUnit(); + if (tu != null) { + CPPVisitor.getDeclarations(tu, this); + return; + } + } + } } /* (non-Javadoc) @@ -192,17 +232,17 @@ public class CPPVariable extends PlatformObject implements ICPPVariable, ICPPInt * @see org.eclipse.cdt.core.dom.ast.IBinding#getNameCharArray() */ public char[] getNameCharArray() { - if (declarations != null) { - return declarations[0].getSimpleID(); + if (fDeclarations != null) { + return fDeclarations[0].getSimpleID(); } - return definition.getSimpleID(); + return fDefinition.getSimpleID(); } /* (non-Javadoc) * @see org.eclipse.cdt.core.dom.ast.IBinding#getScope() */ public IScope getScope() { - return CPPVisitor.getContainingScope(definition != null ? definition : declarations[0]); + return CPPVisitor.getContainingScope(fDefinition != null ? fDefinition : fDeclarations[0]); } /* (non-Javadoc) @@ -321,7 +361,7 @@ public class CPPVariable extends PlatformObject implements ICPPVariable, ICPPInt } public IBinding getOwner() throws DOMException { - IASTName node = definition != null ? definition : declarations[0]; + IASTName node = fDefinition != null ? fDefinition : fDeclarations[0]; return CPPVisitor.findNameOwner(node, !hasStorageClass(IASTDeclSpecifier.sc_extern)); } @@ -335,13 +375,13 @@ public class CPPVariable extends PlatformObject implements ICPPVariable, ICPPInt } public IValue getInitialValue(int maxDepth) { - if (definition != null) { - final IValue val= getInitialValue(definition, maxDepth); + if (fDefinition != null) { + final IValue val= getInitialValue(fDefinition, maxDepth); if (val != null) return val; } - if (declarations != null) { - for (IASTName decl : declarations) { + if (fDeclarations != null) { + for (IASTName decl : fDeclarations) { if (decl == null) break; final IValue val= getInitialValue(decl, maxDepth); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java index 19e18f052c5..d0a9b9561da 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/semantics/CPPSemantics.java @@ -32,6 +32,7 @@ import org.eclipse.cdt.core.dom.ast.EScopeKind; import org.eclipse.cdt.core.dom.ast.IASTArraySubscriptExpression; import org.eclipse.cdt.core.dom.ast.IASTBinaryExpression; import org.eclipse.cdt.core.dom.ast.IASTCastExpression; +import org.eclipse.cdt.core.dom.ast.IASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.IASTCompoundStatement; import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.IASTDeclaration; @@ -115,6 +116,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplatePartialSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassType; import org.eclipse.cdt.core.dom.ast.cpp.ICPPConstructor; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPField; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunction; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate; import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionType; @@ -282,6 +284,10 @@ public class CPPSemantics { binding = e.getProblem(); } } + + if (binding instanceof IProblemBinding) + return binding; + if (binding == null && data.checkClassContainingFriend()) { // 3.4.1-10 if we don't find a name used in a friend declaration in the member declaration's class // we should look in the class granting friendship @@ -418,7 +424,7 @@ public class CPPSemantics { } } - if (binding != null && !(binding instanceof IProblemBinding)) { + if (binding != null) { if (namePropertyInParent == IASTNamedTypeSpecifier.NAME) { if (!(binding instanceof IType || binding instanceof ICPPConstructor)) { IASTNode parent = name.getParent().getParent(); @@ -452,7 +458,7 @@ public class CPPSemantics { // explicit function specializations are found via name resolution, need to // add name as definition and check the declaration specifier. - if (binding instanceof IFunction && !(binding instanceof IProblemBinding)) { + if (binding instanceof IFunction) { if (data.forFunctionDeclaration()) { IASTNode declaration= data.astName; while (declaration instanceof IASTName) @@ -469,6 +475,19 @@ public class CPPSemantics { } } + // Definitions of static fields are found via name resolution, need to add name to + // the binding to get the right type of arrays that may be declared incomplete. + if (binding instanceof ICPPField && data.astName.isDefinition()) { + IASTNode declaration= data.astName; + while (declaration instanceof IASTName) + declaration= declaration.getParent(); + while (declaration instanceof IASTDeclarator) + declaration= declaration.getParent(); + if (declaration.getPropertyInParent() != IASTCompositeTypeSpecifier.MEMBER_DECLARATION) { + ASTInternal.addDefinition(binding, data.astName); + } + } + // If we're still null... if (binding == null) { if (name instanceof ICPPASTQualifiedName && data.forFunctionDeclaration()) { 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 09a9f836d4d..4274d0a8d2c 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 @@ -1204,6 +1204,7 @@ public class CPPVisitor extends ASTQueries { private IBinding[] bindings; private int idx = 0; private int kind; + private char[] requiredName; private static final int KIND_LABEL = 1; private static final int KIND_OBJ_FN = 2; @@ -1217,6 +1218,10 @@ public class CPPVisitor extends ASTQueries { shouldVisitNames = true; this.decls = new IASTName[DEFAULT_LIST_SIZE]; + final String bname= binding.getName(); + if (bname.length() > 0 && !bname.startsWith("operator")) { //$NON-NLS-1$ + requiredName= bname.toCharArray(); + } this.bindings = new IBinding[] {binding}; if (binding instanceof ICPPUsingDeclaration) { this.bindings= ((ICPPUsingDeclaration) binding).getDelegates(); @@ -1240,6 +1245,9 @@ public class CPPVisitor extends ASTQueries { @Override public int visit(IASTName name) { if (name instanceof ICPPASTQualifiedName) return PROCESS_CONTINUE; + if (requiredName != null && !CharArrayUtils.equals(name.getLookupKey(), requiredName)) { + return PROCESS_CONTINUE; + } ASTNodeProperty prop = name.getPropertyInParent(); if (prop == ICPPASTQualifiedName.SEGMENT_NAME)