diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java index d4a07c025c4..83ee0dbb261 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/cpp/ClassTypeHelper.java @@ -830,7 +830,7 @@ public class ClassTypeHelper { return null; } - private static ICPPMethod getMethodInClass(ICPPClassType ct, MethodKind kind, IASTNode point) { + public static ICPPMethod getMethodInClass(ICPPClassType ct, MethodKind kind, IASTNode point) { switch (kind) { case DEFAULT_CTOR: case COPY_CTOR: 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 20fb23c30a8..e5c95a92a0a 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 @@ -22,6 +22,13 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getUltimateTypeUptoPointers; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + import org.eclipse.cdt.core.dom.ast.ASTGenericVisitor; import org.eclipse.cdt.core.dom.ast.ASTNodeProperty; import org.eclipse.cdt.core.dom.ast.ASTVisitor; @@ -207,13 +214,6 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding; import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownType; import org.eclipse.cdt.internal.core.index.IIndexScope; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - /** * Collection of methods to extract information from a C++ translation unit. */ @@ -225,7 +225,7 @@ public class CPPVisitor extends ASTQueries { public static final String BEGIN_STR = "begin"; //$NON-NLS-1$ public static final char[] BEGIN = BEGIN_STR.toCharArray(); public static final char[] END = "end".toCharArray(); //$NON-NLS-1$ - static final String STD = "std"; //$NON-NLS-1$ + public static final String STD = "std"; //$NON-NLS-1$ private static final char[] SIZE_T = "size_t".toCharArray(); //$NON-NLS-1$ private static final char[] PTRDIFF_T = "ptrdiff_t".toCharArray(); //$NON-NLS-1$ private static final char[] TYPE_INFO = "type_info".toCharArray(); //$NON-NLS-1$ 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 dad5e16e527..56ca50d774f 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 @@ -395,6 +395,38 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase { assertDeclared(); } + // namespace std { + // template class shared_ptr {}; + // template class unique_ptr {}; + // } + // class A {}; + // class B {}; + // class C {}; + + // using std::unique_ptr; + // using std::shared_ptr; + // + // struct P { + // ~P(); + // shared_ptr x; + // unique_ptr y; + // }; + // + // struct Q { + // ~Q() {} + // shared_ptr x; + // unique_ptr y; + // }; + // + // void test() { + // shared_ptr x; + // unique_ptr y; + // } + public void testTemplatesAllowingIncompleteParameterType() throws Exception { + assertDefined("B", "C", "shared_ptr", "unique_ptr"); + assertDeclared("A"); + } + // struct A {}; // struct B {}; // struct C {}; 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 9fedffccacb..e07f016b1df 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 @@ -11,6 +11,7 @@ *******************************************************************************/ package org.eclipse.cdt.internal.ui.refactoring.includes; +import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor.STD; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ALLCVQ; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.ARRAY; import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.PTR; @@ -18,6 +19,8 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.getNestedType; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -76,14 +79,17 @@ import org.eclipse.cdt.core.dom.ast.IType; import org.eclipse.cdt.core.dom.ast.ITypedef; import org.eclipse.cdt.core.dom.ast.IVariable; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCatchHandler; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorChainInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTConstructorInitializer; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTDeleteExpression; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNamedTypeSpecifier; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTNewExpression; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTypeId; +import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassScope; 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.ICPPEnumeration; @@ -98,12 +104,14 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition; import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap; import org.eclipse.cdt.core.index.IIndexMacro; import org.eclipse.cdt.core.index.IndexFilter; +import org.eclipse.cdt.core.parser.util.CharArrayUtils; import org.eclipse.cdt.internal.core.dom.parser.ASTNode; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTIdExpression; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPASTName; import org.eclipse.cdt.internal.core.dom.parser.cpp.CPPFunction; 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.semantics.CPPSemantics; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.CPPVisitor; import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.Conversions; @@ -126,6 +134,15 @@ public class BindingClassifier { private final BindingCollector fBindingCollector; private final Set fProcessedDefinedBindings; private final Set fProcessedDeclaredBindings; + private static final Set templatesAllowingIncompleteArgumentType = + Collections.unmodifiableSet(new HashSet(Arrays.asList(new String[] { + "enable_shared_from_this", // 20.7.2.4 //$NON-NLS-1$ + "declval", // 20.2.4 //$NON-NLS-1$ + "default_delete", // 20.7.1.1 //$NON-NLS-1$ + "shared_ptr", // 20.7.2.2 //$NON-NLS-1$ + "unique_ptr", // 20.7.1 //$NON-NLS-1$ + "weak_ptr" // 20.7.2.3 //$NON-NLS-1$ + }))); /** * @param context the context for binding classification @@ -1122,7 +1139,7 @@ public class BindingClassifier { IBinding binding = name.resolveBinding(); if (binding != null) { - if (isInTemplateArgument(name)) { + if (isTemplateArgumentRequiringCompleteType(name)) { // The name is part of a template argument - define the corresponding binding. defineBinding(binding); } else { @@ -1171,9 +1188,41 @@ public class BindingClassifier { /** * Checks if the given name is part of a template argument. */ - public boolean isInTemplateArgument(IASTName name) { + public boolean isTemplateArgumentRequiringCompleteType(IASTName name) { ICPPASTTypeId typeId = CPPVisitor.findAncestorWithType(name, ICPPASTTypeId.class); - return typeId != null && typeId.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT; + if (typeId == null || typeId.getPropertyInParent() != ICPPASTTemplateId.TEMPLATE_ID_ARGUMENT) + return false; + ICPPASTTemplateId templateId = (ICPPASTTemplateId) typeId.getParent(); + IBinding template = templateId.resolveBinding(); + if (template instanceof IProblemBinding) + return true; + IBinding owner = template.getOwner(); + if (!(owner instanceof ICPPNamespace) || + !CharArrayUtils.equals(owner.getNameCharArray(), STD) || owner.getOwner() != null) { + return true; + } + String templateName = template.getName(); + if (!templatesAllowingIncompleteArgumentType.contains(templateName)) + return true; + + // For most templates allowing incomplete argument type a full definition of the argument + // type is required if the destructor is called. Since the AST doen't contain all destructor + // calling points, we have to use an indirect approach by examining the containing scope. + IASTNode parent = templateId.getParent(); + if (!(parent instanceof ICPPASTNamedTypeSpecifier)) + return false; + parent = parent.getParent(); + if (!(parent instanceof IASTSimpleDeclaration)) + return true; + parent = parent.getParent(); + if (!(parent instanceof ICPPASTCompositeTypeSpecifier)) + return true; + ICPPClassScope classScope = ((ICPPASTCompositeTypeSpecifier) parent).getScope(); + ICPPClassType classType = classScope.getClassType(); + ICPPMethod destructor = ClassTypeHelper.getMethodInClass(classType, MethodKind.DTOR, parent); + if (fAst.getDefinitionsInAST(destructor).length != 0) + return true; + return false; } private static boolean isEnumerationWithoutFixedUnderlyingType(IBinding typeBinding) { @@ -1197,4 +1246,4 @@ public class BindingClassifier { } return true; } -} \ No newline at end of file +}