diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java index e8019f0970c..437e9f0b2b7 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/BindingClassifierTest.java @@ -584,6 +584,28 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase { assertDeclared(); } + // class A; + // + // A& f(); + // + // struct A { + // void m(); + // }; + + // template + // void g(T& p) { + // p.m(); + // } + // + // void test() { + // g(f()); + // } + public void testTemplateParameter_514197() throws Exception { + getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true); + assertDefined("A"); + assertDeclared("f"); + } + // namespace std { // template class shared_ptr {}; // template class unique_ptr {}; diff --git a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludeOrganizerTest.java b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludeOrganizerTest.java index c6a672ffe84..be52944b7d1 100644 --- a/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludeOrganizerTest.java +++ b/core/org.eclipse.cdt.ui.tests/ui/org/eclipse/cdt/ui/tests/refactoring/includes/IncludeOrganizerTest.java @@ -715,4 +715,42 @@ public class IncludeOrganizerTest extends IncludesTestBase { preferenceStore.setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true); assertExpectedResults(); } + + //h1.h + //class A; + // + //A& f(); + + //h2.h + //struct A { + // void m(); + //}; + + //source.cpp + //#include "h1.h" + //#include "h2.h" + // + //template + //void g(T& p) { + // p.m(); + //} + // + //void test() { + // g(f()); + //} + //==================== + //#include "h1.h" + //#include "h2.h" + // + //template + //void g(T& p) { + // p.m(); + //} + // + //void test() { + // g(f()); + //} + public void testTemplateParameter_514197() throws Exception { + assertExpectedResults(); + } } diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java index 5c7fa4e546f..17f52971b9a 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/refactoring/includes/BindingClassifier.java @@ -24,6 +24,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Deque; import java.util.HashSet; +import java.util.Iterator; import java.util.Set; import org.eclipse.core.runtime.CoreException; @@ -115,6 +116,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateArgument; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateInstance; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.dom.ast.cpp.ICPPUsingDeclaration; import org.eclipse.cdt.core.index.IIndexFile; @@ -132,6 +134,7 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPReferenceType; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper; import org.eclipse.cdt.internal.core.dom.parser.cpp.ClassTypeHelper.MethodKind; +import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions; @@ -908,6 +911,13 @@ public class BindingClassifier { declareBinding(binding); // Declare the binding of this name. } } + + + if (binding instanceof ICPPTemplateInstance && + !((ICPPTemplateInstance) binding).isExplicitSpecialization() && + isDeclaredLocally(((ICPPTemplateInstance) binding).getSpecializedBinding())) { + fInstancesOfLocallyDefinedTemplates.add((ICPPTemplateInstance) binding); + } } return PROCESS_CONTINUE; } @@ -951,14 +961,15 @@ public class BindingClassifier { private final IncludeCreationContext fContext; private final IncludePreferences fPreferences; /** The bindings which require a full definition. */ - private final Set fBindingsToDefine; + private final Set fBindingsToDefine = new HashSet<>(); /** The bindings which only require a simple forward declaration. */ - private final Set fBindingsToForwardDeclare; + private final Set fBindingsToForwardDeclare = new HashSet<>(); /** The AST that the classifier is working on. */ private IASTTranslationUnit fAst; - private final BindingCollector fBindingCollector; - private final Set fProcessedDefinedBindings; - private final Set fProcessedDeclaredBindings; + private final BindingCollector fBindingCollector = new BindingCollector(); + private final Set fProcessedDefinedBindings = new HashSet<>(); + private final Set fProcessedDeclaredBindings = new HashSet<>(); + public final Set fInstancesOfLocallyDefinedTemplates = new HashSet<>(); /** * @param context the context for binding classification @@ -966,11 +977,6 @@ public class BindingClassifier { public BindingClassifier(IncludeCreationContext context) { fContext = context; fPreferences = context.getPreferences(); - fBindingsToDefine = new HashSet<>(); - fBindingsToForwardDeclare = new HashSet<>(); - fProcessedDefinedBindings = new HashSet<>(); - fProcessedDeclaredBindings = new HashSet<>(); - fBindingCollector = new BindingCollector(); } public void classifyNodeContents(IASTNode node) { @@ -983,11 +989,42 @@ public class BindingClassifier { // target bindings are in a header not reachable via includes. CPPSemantics.enablePromiscuousBindingResolution(); node.accept(fBindingCollector); + postprocessTemplates(); } finally { CPPSemantics.disablePromiscuousBindingResolution(); } } + private void postprocessTemplates() { + Set templatearametersRequiringDefinition = new HashSet<>(); + for (Iterator it = fBindingsToDefine.iterator(); it.hasNext();) { + IBinding binding = it.next(); + if (binding instanceof ICPPTemplateParameter) { + templatearametersRequiringDefinition.add((ICPPTemplateParameter) binding); + it.remove(); + } + } + if (templatearametersRequiringDefinition.isEmpty()) + return; + + for (ICPPTemplateInstance instance : fInstancesOfLocallyDefinedTemplates) { + ICPPTemplateParameterMap parameterMap = instance.getTemplateParameterMap(); + ICPPTemplateParameter[] params = instance.getTemplateDefinition().getTemplateParameters(); + for (ICPPTemplateParameter param : params) { + if (templatearametersRequiringDefinition.contains(param)) { + ICPPTemplateArgument argument = parameterMap.getArgument(param); + if (argument != null) { + defineTemplateArgument(argument); + } else { + for (ICPPTemplateArgument arg : parameterMap.getPackExpansion(param)) { + defineTemplateArgument(arg); + } + } + } + } + } + } + /** * Returns the bindings which require a full definition. */ @@ -1159,8 +1196,9 @@ public class BindingClassifier { IBinding owner = ((IBinding) type).getOwner(); if (owner instanceof ICPPNamespace && (CharArrayUtils.equals(owner.getNameCharArray(), STD) || - CharArrayUtils.equals(owner.getNameCharArray(), "__gnu_cxx"))) //$NON-NLS-1$ + CharArrayUtils.equals(owner.getNameCharArray(), "__gnu_cxx"))) { //$NON-NLS-1$ addRequiredBindings((IBinding) type, queue); + } } } } @@ -1195,10 +1233,14 @@ public class BindingClassifier { } catch (CoreException e) { } } + } else if (binding instanceof ICPPTemplateParameter) { + newBindings.add(binding); + } else if (binding instanceof ICPPUnknownBinding) { + newBindings.add(binding.getOwner()); } else if (binding instanceof ICPPMethod) { newBindings.add(binding); // Include the method in case we need its inline definition. if (binding instanceof ICPPConstructor) - newBindings.add(binding.getOwner()); + newBindings.add(binding.getOwner()); } else if (binding instanceof IType) { // Remove type qualifiers. IBinding b = getTypeBinding((IType) binding); @@ -1225,10 +1267,10 @@ public class BindingClassifier { return; if (fProcessedDefinedBindings.contains(binding)) return; - if (isDeclaredLocally(binding)) - return; // Declared locally. if (!fProcessedDeclaredBindings.add(binding)) return; + if (isDeclaredLocally(binding)) + return; // Declared locally. if (!canForwardDeclare(binding)) { defineBinding(binding); return; @@ -1474,6 +1516,12 @@ public class BindingClassifier { } } + private void defineTemplateArgument(ICPPTemplateArgument argument) { + IType type = argument.getOriginalTypeValue(); + if (type != null) + defineTypeExceptTypedefOrNonFixedEnum(type); + } + private boolean isDefined(IBinding binding) { if (fBindingsToDefine.contains(binding)) return true;