From e6b392ffbc5f86d992cb5ffca98f8a294905303b Mon Sep 17 00:00:00 2001 From: Sergey Prigogin Date: Tue, 24 Jun 2014 20:20:54 -0700 Subject: [PATCH] Bug 438114 - Friend function declaration is not reconciled with other declarations --- .../core/parser/tests/ast2/AST2CPPTests.java | 21 +++++++ .../core/dom/parser/cpp/CPPFunction.java | 57 +++++++++++++++---- .../dom/parser/cpp/CPPFunctionTemplate.java | 46 ++++++++++++--- .../dom/parser/cpp/semantics/CPPVisitor.java | 6 +- 4 files changed, 109 insertions(+), 21 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 8c11b2bc41f..a6fdf220243 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 @@ -6891,6 +6891,27 @@ public class AST2CPPTests extends AST2TestBase { assertSame(g1, g2); } + // template + // class A { + // template + // friend int func(int i); + // }; + // + // template + // int func(int i = 0); + // + // template + // int func(int i) { return i; } + public void testFriendFunction_438114() throws Exception { + BindingAssertionHelper bh = getAssertionHelper(); + ICPPFunction f1= bh.assertNonProblemOnFirstIdentifier("func(int i);"); + ICPPFunction f2= bh.assertNonProblemOnFirstIdentifier("func(int i = 0);"); + ICPPFunction f3= bh.assertNonProblemOnFirstIdentifier("func(int i) {"); + assertSame(f1, f2); + assertSame(f2, f3); + assertEquals(0, f1.getRequiredArgumentCount()); + } + // class A { // public: // void foo() const volatile; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java index af24a0ee9b1..12a5d5c201a 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunction.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2013 IBM Corporation and others. + * Copyright (c) 2004, 2014 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 @@ -29,7 +29,6 @@ import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTParameterDeclaration; import org.eclipse.cdt.core.dom.ast.IASTReturnStatement; import org.eclipse.cdt.core.dom.ast.IASTSimpleDeclaration; -import org.eclipse.cdt.core.dom.ast.IASTStandardFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.IASTStatement; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; import org.eclipse.cdt.core.dom.ast.IASTTypeId; @@ -43,6 +42,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeclSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDeclarator; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTFunctionDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTInitializerClause; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTParameterDeclaration; 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.ICPPFunction; @@ -169,23 +169,46 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt @Override public ICPPParameter[] getParameters() { - IASTStandardFunctionDeclarator dtor = getPreferredDtor(); - if (dtor == null) { + ICPPASTFunctionDeclarator declarator = getDefinition(); + IASTDeclarator[] dtors = getDeclarations(); + if (dtors != null) { + // In case of multiple function declarations we select the one with the most + // default parameter values. + int defaultValuePosition = -1; + for (IASTDeclarator dtor : dtors) { + if (dtor instanceof ICPPASTFunctionDeclarator) { + if (declarator == null) { + declarator = (ICPPASTFunctionDeclarator) dtor; + } else { + ICPPASTFunctionDeclarator contender = (ICPPASTFunctionDeclarator) dtor; + if (defaultValuePosition < 0) + defaultValuePosition = findFirstDefaultValue(declarator.getParameters()); + int pos = findFirstDefaultValue(contender.getParameters()); + if (pos < defaultValuePosition) { + declarator = contender; + defaultValuePosition = pos; + } + } + } + } + } + + if (declarator == null) { return CPPBuiltinParameter.createParameterList(getType()); } - IASTParameterDeclaration[] params = dtor.getParameters(); + IASTParameterDeclaration[] params = declarator.getParameters(); int size = params.length; ICPPParameter[] result = new ICPPParameter[size]; if (size > 0) { for (int i = 0; i < size; i++) { - IASTParameterDeclaration p = params[i]; - final IASTName name = getParamName(p); + IASTParameterDeclaration param = params[i]; + final IASTName name = getParamName(param); final IBinding binding= name.resolveBinding(); if (binding instanceof ICPPParameter) { result[i]= (ICPPParameter) binding; } else { - result[i] = new CPPParameter.CPPParameterProblem(p, - IProblemBinding.SEMANTIC_INVALID_TYPE, name.toCharArray()); + result[i] = new CPPParameter.CPPParameterProblem( + param, IProblemBinding.SEMANTIC_INVALID_TYPE, name.toCharArray()); } } @@ -195,6 +218,18 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt return result; } + /** + * Returns the position of the first parameter that has a default value. + * If none of the parameters has a default value, return the number of parameters. + */ + static int findFirstDefaultValue(ICPPASTParameterDeclaration[] parameters) { + for (int i = parameters.length; --i >= 0;) { + if (parameters[i].getDeclarator().getInitializer() == null) + return i + 1; + } + return 0; + } + @Override public IScope getFunctionScope() { resolveAllDeclarations(); @@ -595,10 +630,10 @@ public class CPPFunction extends PlatformObject implements ICPPFunction, ICPPInt if (dtors != null) { for (IASTDeclarator declarator : dtors) { if (declarator instanceof ICPPASTFunctionDeclarator) - return (ICPPASTFunctionDeclarator) declarator; + return (ICPPASTFunctionDeclarator) declarator; } } - return null; + return dtor; } @Override diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java index 35cdc0089f1..24e683d50ed 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/CPPFunctionTemplate.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2005, 2012 IBM Corporation and others. + * Copyright (c) 2005, 2014 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 @@ -46,7 +46,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.EvalFixed; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil; /** - * Implementation of function templates + * Implementation of function templates. */ public class CPPFunctionTemplate extends CPPTemplateDefinition implements ICPPFunctionTemplate, ICPPInternalFunction { @@ -99,23 +99,51 @@ public class CPPFunctionTemplate extends CPPTemplateDefinition @Override public ICPPParameter[] getParameters() { - ICPPASTFunctionDeclarator fdecl= getFirstFunctionDtor(); - if (fdecl != null) { - IASTParameterDeclaration[] params = fdecl.getParameters(); + ICPPASTFunctionDeclarator declarator= null; + IASTDeclarator dtor= getDeclaratorByName(getDefinition()); + if (dtor instanceof ICPPASTFunctionDeclarator) + declarator = (ICPPASTFunctionDeclarator) dtor; + + IASTNode[] decls = getDeclarations(); + if (decls != null) { + // In case of multiple function declarations we select the one with the most + // default parameter values. + int defaultValuePosition = -1; + for (IASTNode decl : decls) { + dtor= getDeclaratorByName(decl); + if (dtor instanceof ICPPASTFunctionDeclarator) { + if (declarator == null) { + declarator = (ICPPASTFunctionDeclarator) dtor; + } else { + ICPPASTFunctionDeclarator contender = (ICPPASTFunctionDeclarator) dtor; + if (defaultValuePosition < 0) + defaultValuePosition = CPPFunction.findFirstDefaultValue(declarator.getParameters()); + int pos = CPPFunction.findFirstDefaultValue(contender.getParameters()); + if (pos < defaultValuePosition) { + declarator = contender; + defaultValuePosition = pos; + } + } + } + } + } + + if (declarator != null) { + IASTParameterDeclaration[] params = declarator.getParameters(); int size = params.length; if (size == 0) { return ICPPParameter.EMPTY_CPPPARAMETER_ARRAY; } ICPPParameter[] result = new ICPPParameter[size]; for (int i = 0; i < size; i++) { - IASTParameterDeclaration p = params[i]; - final IASTName pname = ASTQueries.findInnermostDeclarator(p.getDeclarator()).getName(); + IASTParameterDeclaration param = params[i]; + final IASTName pname = ASTQueries.findInnermostDeclarator(param.getDeclarator()).getName(); final IBinding binding= pname.resolveBinding(); if (binding instanceof ICPPParameter) { result[i]= (ICPPParameter) binding; } else { - result[i] = new CPPParameter.CPPParameterProblem(p, - IProblemBinding.SEMANTIC_INVALID_TYPE, pname.toCharArray()); + result[i] = new CPPParameter.CPPParameterProblem( + param, IProblemBinding.SEMANTIC_INVALID_TYPE, pname.toCharArray()); } } 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 3adc2734c23..c79dee6062a 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2013 IBM Corporation and others. + * Copyright (c) 2004, 2014 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 @@ -171,6 +171,7 @@ import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ASTInternal; import org.eclipse.cdt.internal.core.dom.parser.ASTQueries; import org.eclipse.cdt.internal.core.dom.parser.ASTTranslationUnit; +import org.eclipse.cdt.internal.core.dom.parser.IASTInternalScope; import org.eclipse.cdt.internal.core.dom.parser.ProblemBinding; import org.eclipse.cdt.internal.core.dom.parser.ProblemType; import org.eclipse.cdt.internal.core.dom.parser.SizeofCalculator; @@ -896,6 +897,9 @@ public class CPPVisitor extends ASTQueries { : new CPPFunction(typeRelevantDtor); } binding= CPPSemantics.checkDeclSpecifier(binding, name, parent); + if (isFriendDecl && scope instanceof IASTInternalScope) { + ((IASTInternalScope) scope).addBinding(binding); + } } return binding;