mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-09-09 11:33:20 +02:00
Bug 422695 - Organize Includes does not add include for template
parameter of unique_ptr, etc.
This commit is contained in:
parent
2eb80a6d34
commit
e9e53fb9fa
3 changed files with 115 additions and 28 deletions
|
@ -168,12 +168,15 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// struct A { void m(); };
|
// struct A { void m(); };
|
||||||
// class B : public A {};
|
// class B : public A {};
|
||||||
// B b;
|
// B b;
|
||||||
|
// class C : public A {};
|
||||||
|
// C c;
|
||||||
|
|
||||||
// void test() {
|
// void test() {
|
||||||
// b.m();
|
// b.m();
|
||||||
|
// c->m();
|
||||||
// }
|
// }
|
||||||
public void testClassHierarchy() throws Exception {
|
public void testClassHierarchy() throws Exception {
|
||||||
assertDefined("b", "B");
|
assertDefined("b", "B", "c", "C");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -472,11 +475,53 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// shared_ptr<C> x;
|
// shared_ptr<C> x;
|
||||||
// unique_ptr<C> y;
|
// unique_ptr<C> y;
|
||||||
// }
|
// }
|
||||||
public void testTemplatesAllowingIncompleteParameterType() throws Exception {
|
public void testTemplatesAllowingIncompleteParameterType_1() throws Exception {
|
||||||
assertDefined("B", "C", "shared_ptr", "unique_ptr");
|
assertDefined("B", "C", "shared_ptr", "unique_ptr");
|
||||||
assertDeclared("A");
|
assertDeclared("A");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// namespace std {
|
||||||
|
// template<typename T>
|
||||||
|
// struct unique_ptr {
|
||||||
|
// T* operator->();
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// struct A {
|
||||||
|
// void m();
|
||||||
|
// };
|
||||||
|
// class B : public A {
|
||||||
|
// };
|
||||||
|
// std::unique_ptr<B> b;
|
||||||
|
|
||||||
|
// void test() {
|
||||||
|
// b->m();
|
||||||
|
// }
|
||||||
|
public void testTemplatesAllowingIncompleteParameterType_2() throws Exception {
|
||||||
|
assertDefined("B", "b");
|
||||||
|
assertDeclared();
|
||||||
|
}
|
||||||
|
|
||||||
|
// namespace std {
|
||||||
|
// template<typename T>
|
||||||
|
// struct shared_ptr {
|
||||||
|
// T* operator->();
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// struct A {
|
||||||
|
// void m();
|
||||||
|
// };
|
||||||
|
// class B : public A {
|
||||||
|
// };
|
||||||
|
// std::shared_ptr<B> f();
|
||||||
|
|
||||||
|
// void test() {
|
||||||
|
// f()->m();
|
||||||
|
// }
|
||||||
|
public void testTemplatesAllowingIncompleteParameterType_3() throws Exception {
|
||||||
|
assertDefined("B", "f");
|
||||||
|
assertDeclared();
|
||||||
|
}
|
||||||
|
|
||||||
// struct A {};
|
// struct A {};
|
||||||
// struct B {};
|
// struct B {};
|
||||||
// struct C {};
|
// struct C {};
|
||||||
|
|
|
@ -18,11 +18,10 @@ import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUti
|
||||||
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
|
import static org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil.REF;
|
||||||
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.getNestedType;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.core.runtime.CoreException;
|
import org.eclipse.core.runtime.CoreException;
|
||||||
|
@ -105,6 +104,7 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPReferenceType;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPSpecialization;
|
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.ICPPTemplateArgument;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateDefinition;
|
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.ICPPTemplateParameterMap;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameterMap;
|
||||||
import org.eclipse.cdt.core.index.IIndexMacro;
|
import org.eclipse.cdt.core.index.IIndexMacro;
|
||||||
import org.eclipse.cdt.core.index.IndexFilter;
|
import org.eclipse.cdt.core.index.IndexFilter;
|
||||||
|
@ -305,8 +305,8 @@ public class BindingClassifier {
|
||||||
* @return The binding(s) which is/are suitable for either declaration or definition,
|
* @return The binding(s) which is/are suitable for either declaration or definition,
|
||||||
* or an empty list if no such binding is available.
|
* or an empty list if no such binding is available.
|
||||||
*/
|
*/
|
||||||
private List<IBinding> getRequiredBindings(IBinding binding) {
|
private Set<IBinding> getRequiredBindings(IBinding binding) {
|
||||||
List<IBinding> bindings = new ArrayList<IBinding>();
|
Set<IBinding> bindings = new HashSet<IBinding>();
|
||||||
|
|
||||||
if (binding instanceof ICPPMember) {
|
if (binding instanceof ICPPMember) {
|
||||||
// If the binding is a member, get its owning composite type.
|
// If the binding is a member, get its owning composite type.
|
||||||
|
@ -401,7 +401,7 @@ public class BindingClassifier {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IBinding> requiredBindings = getRequiredBindings(binding);
|
Collection<IBinding> requiredBindings = getRequiredBindings(binding);
|
||||||
|
|
||||||
for (IBinding requiredBinding : requiredBindings) {
|
for (IBinding requiredBinding : requiredBindings) {
|
||||||
if (fBindingsToDeclare.contains(requiredBinding) || fBindingsToDefine.contains(requiredBinding)) {
|
if (fBindingsToDeclare.contains(requiredBinding) || fBindingsToDefine.contains(requiredBinding)) {
|
||||||
|
@ -431,14 +431,14 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether the binding can be forward declared or not.
|
* Checks whether the binding can be forward declared or not according to preferences.
|
||||||
*/
|
*/
|
||||||
private boolean canForwardDeclare(IBinding binding) {
|
private boolean canForwardDeclare(IBinding binding) {
|
||||||
boolean canDeclare = false;
|
boolean canDeclare = false;
|
||||||
if (binding instanceof ICompositeType) {
|
if (binding instanceof ICompositeType) {
|
||||||
canDeclare = fPreferences.forwardDeclareCompositeTypes;
|
canDeclare = fPreferences.forwardDeclareCompositeTypes;
|
||||||
} else if (binding instanceof IEnumeration) {
|
} else if (binding instanceof IEnumeration) {
|
||||||
canDeclare = fPreferences.forwardDeclareEnums;
|
canDeclare = fPreferences.forwardDeclareEnums && isEnumerationWithoutFixedUnderlyingType(binding);
|
||||||
} else if (binding instanceof IFunction && !(binding instanceof ICPPMethod)) {
|
} else if (binding instanceof IFunction && !(binding instanceof ICPPMethod)) {
|
||||||
canDeclare = fPreferences.forwardDeclareFunctions;
|
canDeclare = fPreferences.forwardDeclareFunctions;
|
||||||
} else if (binding instanceof IVariable) {
|
} else if (binding instanceof IVariable) {
|
||||||
|
@ -453,6 +453,22 @@ public class BindingClassifier {
|
||||||
return canDeclare;
|
return canDeclare;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the type may be forward declared according to language rules.
|
||||||
|
*/
|
||||||
|
private boolean mayBeForwardDeclared(IType type) {
|
||||||
|
IBinding binding = getTypeBinding(type);
|
||||||
|
if (binding == null)
|
||||||
|
return false;
|
||||||
|
if (!fPreferences.assumeTemplatesMayBeForwardDeclared &&
|
||||||
|
(binding instanceof ICPPTemplateDefinition || binding instanceof ICPPSpecialization)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (binding instanceof ICompositeType)
|
||||||
|
return true;
|
||||||
|
return binding instanceof ICPPEnumeration && ((ICPPEnumeration) binding).getFixedType() != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the given type to the list of bindings which have to be defined. Typedefs and
|
* Adds the given type to the list of bindings which have to be defined. Typedefs and
|
||||||
* enumerations without fixed underlying type are skipped since they must be defined in the file
|
* enumerations without fixed underlying type are skipped since they must be defined in the file
|
||||||
|
@ -481,7 +497,7 @@ public class BindingClassifier {
|
||||||
if (fAst.getDefinitionsInAST(binding).length != 0)
|
if (fAst.getDefinitionsInAST(binding).length != 0)
|
||||||
return; // Defined locally.
|
return; // Defined locally.
|
||||||
|
|
||||||
List<IBinding> requiredBindings = getRequiredBindings(binding);
|
Collection<IBinding> requiredBindings = getRequiredBindings(binding);
|
||||||
for (IBinding requiredBinding : requiredBindings) {
|
for (IBinding requiredBinding : requiredBindings) {
|
||||||
fBindingsToDeclare.remove(requiredBinding);
|
fBindingsToDeclare.remove(requiredBinding);
|
||||||
if (requiredBinding == binding) {
|
if (requiredBinding == binding) {
|
||||||
|
@ -540,22 +556,37 @@ public class BindingClassifier {
|
||||||
|
|
||||||
// Handle return or expression type of the function or constructor call.
|
// Handle return or expression type of the function or constructor call.
|
||||||
IType returnType = function.getType().getReturnType();
|
IType returnType = function.getType().getReturnType();
|
||||||
if (!(returnType instanceof IPointerType) && !(returnType instanceof ICPPReferenceType)) {
|
defineTypeOfBinding(function, returnType);
|
||||||
// The return type needs a full definition.
|
|
||||||
defineTypeExceptTypedefOrNonFixedEnum(returnType);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle parameters.
|
// Handle parameters.
|
||||||
processFunctionParameters(function, arguments);
|
processFunctionParameters(function, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void defineTypeOfBinding(IBinding binding, IType type) {
|
||||||
|
if (fBindingsToDefine.contains(binding) && !mayBeForwardDeclared(type)) {
|
||||||
|
if (type instanceof ICPPTemplateInstance) {
|
||||||
|
ICPPTemplateInstance instance = (ICPPTemplateInstance) type;
|
||||||
|
IBinding template = instance.getSpecializedBinding();
|
||||||
|
if (templatesAllowingIncompleteArgumentType.contains(template.getName())) {
|
||||||
|
ICPPTemplateArgument[] arguments = instance.getTemplateArguments();
|
||||||
|
if (arguments.length != 0) {
|
||||||
|
IType argumentType = arguments[0].getTypeValue();
|
||||||
|
defineTypeExceptTypedefOrNonFixedEnum(argumentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!(type instanceof IPointerType) && !(type instanceof ICPPReferenceType)) {
|
||||||
|
defineTypeExceptTypedefOrNonFixedEnum(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class BindingCollector extends ASTVisitor {
|
private class BindingCollector extends ASTVisitor {
|
||||||
BindingCollector() {
|
BindingCollector() {
|
||||||
super(true);
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTDeclaration declaration) {
|
public int leave(IASTDeclaration declaration) {
|
||||||
if (declaration instanceof IASTSimpleDeclaration) {
|
if (declaration instanceof IASTSimpleDeclaration) {
|
||||||
/*
|
/*
|
||||||
* The type specifier of a simple declaration of a variable must always be defined
|
* The type specifier of a simple declaration of a variable must always be defined
|
||||||
|
@ -614,7 +645,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTDeclarator declarator) {
|
public int leave(IASTDeclarator declarator) {
|
||||||
if (declarator instanceof IASTFunctionDeclarator) {
|
if (declarator instanceof IASTFunctionDeclarator) {
|
||||||
/*
|
/*
|
||||||
* The type specifier of a function definition doesn't need to be defined if it is
|
* The type specifier of a function definition doesn't need to be defined if it is
|
||||||
|
@ -668,7 +699,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTDeclSpecifier declSpec) {
|
public int leave(IASTDeclSpecifier declSpec) {
|
||||||
if (declSpec instanceof IASTElaboratedTypeSpecifier) {
|
if (declSpec instanceof IASTElaboratedTypeSpecifier) {
|
||||||
/*
|
/*
|
||||||
* The type specifier of an elaborated type neither needs to be defined nor needs to be
|
* The type specifier of an elaborated type neither needs to be defined nor needs to be
|
||||||
|
@ -684,7 +715,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(ICPPASTBaseSpecifier baseSpecifier) {
|
public int leave(ICPPASTBaseSpecifier baseSpecifier) {
|
||||||
/*
|
/*
|
||||||
* The type of a base specifier must always be defined.
|
* The type of a base specifier must always be defined.
|
||||||
*
|
*
|
||||||
|
@ -696,7 +727,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTInitializer initializer) {
|
public int leave(IASTInitializer initializer) {
|
||||||
/*
|
/*
|
||||||
* The type of the member of a constructor chain initializer doesn't need to be defined
|
* The type of the member of a constructor chain initializer doesn't need to be defined
|
||||||
* if it is a pointer or reference type and if the argument type matches.
|
* if it is a pointer or reference type and if the argument type matches.
|
||||||
|
@ -799,7 +830,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTStatement statement) {
|
public int leave(IASTStatement statement) {
|
||||||
if (statement instanceof IASTReturnStatement) {
|
if (statement instanceof IASTReturnStatement) {
|
||||||
/*
|
/*
|
||||||
* The type of the return value expression doesn't need to be defined if the actual
|
* The type of the return value expression doesn't need to be defined if the actual
|
||||||
|
@ -869,7 +900,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTExpression expression) {
|
public int leave(IASTExpression expression) {
|
||||||
ASTNodeProperty propertyInParent = expression.getPropertyInParent();
|
ASTNodeProperty propertyInParent = expression.getPropertyInParent();
|
||||||
if (propertyInParent == IASTIfStatement.CONDITION
|
if (propertyInParent == IASTIfStatement.CONDITION
|
||||||
|| propertyInParent == IASTForStatement.CONDITION
|
|| propertyInParent == IASTForStatement.CONDITION
|
||||||
|
@ -906,10 +937,8 @@ public class BindingClassifier {
|
||||||
IBinding binding = idExpression.getName().resolveBinding();
|
IBinding binding = idExpression.getName().resolveBinding();
|
||||||
if (binding instanceof IVariable) {
|
if (binding instanceof IVariable) {
|
||||||
// Get the declared type.
|
// Get the declared type.
|
||||||
IType expressionType = ((IVariable) binding).getType();
|
IType variableType = ((IVariable) binding).getType();
|
||||||
if (!(expressionType instanceof IPointerType) && !(expressionType instanceof ICPPReferenceType)) {
|
defineTypeOfBinding(binding, variableType);
|
||||||
defineTypeExceptTypedefOrNonFixedEnum(expressionType);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (expression instanceof IASTUnaryExpression) {
|
} else if (expression instanceof IASTUnaryExpression) {
|
||||||
/*
|
/*
|
||||||
|
@ -1104,7 +1133,14 @@ public class BindingClassifier {
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defineTypeExceptTypedefOrNonFixedEnum(((IASTFieldReference) expression).getFieldOwner().getExpressionType());
|
IASTExpression fieldOwner = ((IASTFieldReference) expression).getFieldOwner();
|
||||||
|
IType expressionType = fieldOwner.getExpressionType();
|
||||||
|
if (!(fieldOwner instanceof IASTIdExpression || fieldOwner instanceof IASTFunctionCallExpression) ||
|
||||||
|
expressionType instanceof IPointerType || expressionType instanceof ICPPReferenceType) {
|
||||||
|
// Id expressions and function call expressions returning non pointer and
|
||||||
|
// non reference types are processed separately.
|
||||||
|
defineTypeExceptTypedefOrNonFixedEnum(expressionType);
|
||||||
|
}
|
||||||
} else if (expression instanceof ICPPASTNewExpression) {
|
} else if (expression instanceof ICPPASTNewExpression) {
|
||||||
/*
|
/*
|
||||||
* The type specifier of a "new" expression always requires a definition.
|
* The type specifier of a "new" expression always requires a definition.
|
||||||
|
@ -1153,7 +1189,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTName name) {
|
public int leave(IASTName name) {
|
||||||
if (isPartOfExternalMacroDefinition(name))
|
if (isPartOfExternalMacroDefinition(name))
|
||||||
return PROCESS_CONTINUE;
|
return PROCESS_CONTINUE;
|
||||||
|
|
||||||
|
@ -1188,7 +1224,7 @@ public class BindingClassifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int visit(IASTTranslationUnit tu) {
|
public int leave(IASTTranslationUnit tu) {
|
||||||
for (IASTPreprocessorMacroExpansion macroExpansion : tu.getMacroExpansions()) {
|
for (IASTPreprocessorMacroExpansion macroExpansion : tu.getMacroExpansions()) {
|
||||||
IASTPreprocessorMacroDefinition macroDefinition = macroExpansion.getMacroDefinition();
|
IASTPreprocessorMacroDefinition macroDefinition = macroExpansion.getMacroDefinition();
|
||||||
IASTName name = macroDefinition.getName();
|
IASTName name = macroDefinition.getName();
|
||||||
|
|
|
@ -45,6 +45,7 @@ public class IncludePreferences implements Comparator<StyledInclude> {
|
||||||
public final boolean forwardDeclareExternalVariables;
|
public final boolean forwardDeclareExternalVariables;
|
||||||
public final boolean forwardDeclareTemplates;
|
public final boolean forwardDeclareTemplates;
|
||||||
public final boolean forwardDeclareNamespaceElements;
|
public final boolean forwardDeclareNamespaceElements;
|
||||||
|
public final boolean assumeTemplatesMayBeForwardDeclared;
|
||||||
public final UnusedStatementDisposition unusedStatementsDisposition;
|
public final UnusedStatementDisposition unusedStatementsDisposition;
|
||||||
public final String[] partnerFileSuffixes;
|
public final String[] partnerFileSuffixes;
|
||||||
|
|
||||||
|
@ -84,6 +85,11 @@ public class IncludePreferences implements Comparator<StyledInclude> {
|
||||||
forwardDeclareNamespaceElements = PreferenceConstants.getPreference(
|
forwardDeclareNamespaceElements = PreferenceConstants.getPreference(
|
||||||
PreferenceConstants.FORWARD_DECLARE_NAMESPACE_ELEMENTS, project, true);
|
PreferenceConstants.FORWARD_DECLARE_NAMESPACE_ELEMENTS, project, true);
|
||||||
|
|
||||||
|
// Although templates may be forward declared, it is done so rarely that we assume that it
|
||||||
|
// never happens.
|
||||||
|
// TODO(sprigogin): Create a preference for this.
|
||||||
|
assumeTemplatesMayBeForwardDeclared = false;
|
||||||
|
|
||||||
String value = PreferenceConstants.getPreference(
|
String value = PreferenceConstants.getPreference(
|
||||||
PreferenceConstants.INCLUDES_PARTNER_FILE_SUFFIXES, project, DEFAULT_PARTNER_FILE_SUFFIXES);
|
PreferenceConstants.INCLUDES_PARTNER_FILE_SUFFIXES, project, DEFAULT_PARTNER_FILE_SUFFIXES);
|
||||||
partnerFileSuffixes = value.split(","); //$NON-NLS-1$
|
partnerFileSuffixes = value.split(","); //$NON-NLS-1$
|
||||||
|
|
Loading…
Add table
Reference in a new issue