mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-06-07 17:56:01 +02:00
Bug 432651 - Organize Includes removes an include necessary for defining
a method
This commit is contained in:
parent
41b9049afa
commit
5c7a64d0fb
7 changed files with 200 additions and 103 deletions
|
@ -349,17 +349,18 @@ public abstract class ArrayUtil {
|
||||||
* Adds all elements of an array to a collection.
|
* Adds all elements of an array to a collection.
|
||||||
* @since 5.4
|
* @since 5.4
|
||||||
*/
|
*/
|
||||||
public static <T> void addAll(Collection<T> collection, T[] array) {
|
@SafeVarargs
|
||||||
|
public static <T> void addAll(Collection<? super T> collection, T... elements) {
|
||||||
if (collection instanceof ArrayList) {
|
if (collection instanceof ArrayList) {
|
||||||
((ArrayList<T>) collection).ensureCapacity(collection.size() + array.length);
|
((ArrayList<?>) collection).ensureCapacity(collection.size() + elements.length);
|
||||||
}
|
}
|
||||||
for (T element : array) {
|
for (T element : elements) {
|
||||||
collection.add(element);
|
collection.add(element);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the specified array contains the specified object. Comparison is by
|
* Returns whether the specified array contains the specified object. The comparison is by
|
||||||
* object identity.
|
* object identity.
|
||||||
*
|
*
|
||||||
* @param array the array to search
|
* @param array the array to search
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
|
|
||||||
private void assertDeclared(String... names) {
|
private void assertDeclared(String... names) {
|
||||||
classifyBindings();
|
classifyBindings();
|
||||||
assertExpectedBindings(names, fBindingClassifier.getBindingsToDeclare(), "declared");
|
assertExpectedBindings(names, fBindingClassifier.getBindingsToForwardDeclare(), "declared");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertExpectedBindings(String[] expectedNames, Set<IBinding> bindings, String verb) {
|
private void assertExpectedBindings(String[] expectedNames, Set<IBinding> bindings, String verb) {
|
||||||
|
@ -176,7 +176,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// c->m();
|
// c->m();
|
||||||
// }
|
// }
|
||||||
public void testClassHierarchy() throws Exception {
|
public void testClassHierarchy() throws Exception {
|
||||||
assertDefined("b", "B", "c", "C");
|
assertDefined("b", "B", "c", "C", "m");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// a->m();
|
// a->m();
|
||||||
// }
|
// }
|
||||||
public void testMethodCall() throws Exception {
|
public void testMethodCall() throws Exception {
|
||||||
assertDefined("A");
|
assertDefined("A", "m");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true);
|
getPreferenceStore().setValue(PreferenceConstants.FORWARD_DECLARE_FUNCTIONS, true);
|
||||||
// A header declaring the function is not responsible for defining the parameter type since
|
// A header declaring the function is not responsible for defining the parameter type since
|
||||||
// the implicit conversion from B to A is provided externally to parameter type.
|
// the implicit conversion from B to A is provided externally to parameter type.
|
||||||
assertDefined("B");
|
assertDefined("B", "A");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,6 +337,17 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
assertDeclared("A");
|
assertDeclared("A");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// class A {
|
||||||
|
// void m();
|
||||||
|
// };
|
||||||
|
|
||||||
|
// void A::m() {
|
||||||
|
// }
|
||||||
|
public void testMethodDefinition() throws Exception {
|
||||||
|
assertDefined("A");
|
||||||
|
assertDeclared();
|
||||||
|
}
|
||||||
|
|
||||||
// struct A {
|
// struct A {
|
||||||
// A(const char* s);
|
// A(const char* s);
|
||||||
// };
|
// };
|
||||||
|
@ -384,7 +395,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// a(1);
|
// a(1);
|
||||||
// }
|
// }
|
||||||
public void testCallOperator() throws Exception {
|
public void testCallOperator() throws Exception {
|
||||||
assertDefined("A", "a");
|
assertDefined("A", "a", "operator ()");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +508,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// b->m();
|
// b->m();
|
||||||
// }
|
// }
|
||||||
public void testTemplatesAllowingIncompleteParameterType_2() throws Exception {
|
public void testTemplatesAllowingIncompleteParameterType_2() throws Exception {
|
||||||
assertDefined("B", "b");
|
assertDefined("B", "b", "m");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -520,7 +531,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// c->x->m();
|
// c->x->m();
|
||||||
// }
|
// }
|
||||||
public void testTemplatesAllowingIncompleteParameterType_3() throws Exception {
|
public void testTemplatesAllowingIncompleteParameterType_3() throws Exception {
|
||||||
assertDefined("B", "C");
|
assertDefined("B", "C", "m");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -541,7 +552,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// f()->m();
|
// f()->m();
|
||||||
// }
|
// }
|
||||||
public void testTemplatesAllowingIncompleteParameterType_4() throws Exception {
|
public void testTemplatesAllowingIncompleteParameterType_4() throws Exception {
|
||||||
assertDefined("B", "f");
|
assertDefined("B", "f", "m");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -564,7 +575,7 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
// c->f()->m();
|
// c->f()->m();
|
||||||
// }
|
// }
|
||||||
public void testTemplatesAllowingIncompleteParameterType_5() throws Exception {
|
public void testTemplatesAllowingIncompleteParameterType_5() throws Exception {
|
||||||
assertDefined("B", "C");
|
assertDefined("B", "C", "f", "m");
|
||||||
assertDeclared();
|
assertDeclared();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -473,6 +473,37 @@ public class IncludeOrganizerTest extends IncludesTestBase {
|
||||||
assertExpectedResults();
|
assertExpectedResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//h1.h
|
||||||
|
//struct A {
|
||||||
|
// template <typename T>
|
||||||
|
// void m(const T& p);
|
||||||
|
//};
|
||||||
|
|
||||||
|
//h2.h
|
||||||
|
//#include "h1.h"
|
||||||
|
//template<typename T>
|
||||||
|
//void A::m(const T& p) {
|
||||||
|
//}
|
||||||
|
|
||||||
|
//h3.h
|
||||||
|
//#include "h1.h"
|
||||||
|
//typedef A B;
|
||||||
|
|
||||||
|
//source.cpp
|
||||||
|
//void test(B& b) {
|
||||||
|
// b.m(1);
|
||||||
|
//}
|
||||||
|
//====================
|
||||||
|
//#include "h2.h"
|
||||||
|
//#include "h3.h"
|
||||||
|
//
|
||||||
|
//void test(B& b) {
|
||||||
|
// b.m(1);
|
||||||
|
//}
|
||||||
|
public void testMethodDefinedInHeader() throws Exception {
|
||||||
|
assertExpectedResults();
|
||||||
|
}
|
||||||
|
|
||||||
//h1.h
|
//h1.h
|
||||||
//namespace ns3 {
|
//namespace ns3 {
|
||||||
//class C {};
|
//class C {};
|
||||||
|
|
|
@ -69,7 +69,7 @@ public class InclusionContext {
|
||||||
return fCurrentDirectory;
|
return fCurrentDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IncludePreferences getPreferences() {
|
public final IncludePreferences getPreferences() {
|
||||||
return fPreferences;
|
return fPreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,9 +18,11 @@ 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.ArrayDeque;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Deque;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
@ -127,26 +129,28 @@ import org.eclipse.cdt.internal.core.dom.parser.cpp.semantics.SemanticUtil;
|
||||||
* must be defined and a set of bindings that must be declared.
|
* must be defined and a set of bindings that must be declared.
|
||||||
*/
|
*/
|
||||||
public class BindingClassifier {
|
public class BindingClassifier {
|
||||||
|
public enum InclusionType { DECLARATION, DEFINITION }
|
||||||
|
|
||||||
private final IncludeCreationContext fContext;
|
private final IncludeCreationContext fContext;
|
||||||
private final IncludePreferences fPreferences;
|
private final IncludePreferences fPreferences;
|
||||||
/** The bindings which require a full definition. */
|
/** The bindings which require a full definition. */
|
||||||
private final Set<IBinding> fBindingsToDefine;
|
private final Set<IBinding> fBindingsToDefine;
|
||||||
/** The bindings which only require a simple forward declaration. */
|
/** The bindings which only require a simple forward declaration. */
|
||||||
private final Set<IBinding> fBindingsToDeclare;
|
private final Set<IBinding> fBindingsToForwardDeclare;
|
||||||
/** The AST that the classifier is working on. */
|
/** The AST that the classifier is working on. */
|
||||||
private IASTTranslationUnit fAst;
|
private IASTTranslationUnit fAst;
|
||||||
private final BindingCollector fBindingCollector;
|
private final BindingCollector fBindingCollector;
|
||||||
private final Set<IBinding> fProcessedDefinedBindings;
|
private final Set<IBinding> fProcessedDefinedBindings;
|
||||||
private final Set<IBinding> fProcessedDeclaredBindings;
|
private final Set<IBinding> fProcessedDeclaredBindings;
|
||||||
private static final Set<String> templatesAllowingIncompleteArgumentType =
|
private static final String[] TEMPLATES_ALLOWING_INCOMPLETE_ARGUMENT_TYPE = {
|
||||||
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(new String[] {
|
// Please keep alphabetical order.
|
||||||
"enable_shared_from_this", // 20.7.2.4 //$NON-NLS-1$
|
"enable_shared_from_this", // 20.7.2.4 //$NON-NLS-1$
|
||||||
"declval", // 20.2.4 //$NON-NLS-1$
|
"declval", // 20.2.4 //$NON-NLS-1$
|
||||||
"default_delete", // 20.7.1.1 //$NON-NLS-1$
|
"default_delete", // 20.7.1.1 //$NON-NLS-1$
|
||||||
"shared_ptr", // 20.7.2.2 //$NON-NLS-1$
|
"shared_ptr", // 20.7.2.2 //$NON-NLS-1$
|
||||||
"unique_ptr", // 20.7.1 //$NON-NLS-1$
|
"unique_ptr", // 20.7.1 //$NON-NLS-1$
|
||||||
"weak_ptr" // 20.7.2.3 //$NON-NLS-1$
|
"weak_ptr" // 20.7.2.3 //$NON-NLS-1$
|
||||||
})));
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param context the context for binding classification
|
* @param context the context for binding classification
|
||||||
|
@ -154,10 +158,10 @@ public class BindingClassifier {
|
||||||
public BindingClassifier(IncludeCreationContext context) {
|
public BindingClassifier(IncludeCreationContext context) {
|
||||||
fContext = context;
|
fContext = context;
|
||||||
fPreferences = context.getPreferences();
|
fPreferences = context.getPreferences();
|
||||||
fBindingsToDefine = new HashSet<IBinding>();
|
fBindingsToDefine = new HashSet<>();
|
||||||
fBindingsToDeclare = new HashSet<IBinding>();
|
fBindingsToForwardDeclare = new HashSet<>();
|
||||||
fProcessedDefinedBindings = new HashSet<IBinding>();
|
fProcessedDefinedBindings = new HashSet<>();
|
||||||
fProcessedDeclaredBindings = new HashSet<IBinding>();
|
fProcessedDeclaredBindings = new HashSet<>();
|
||||||
fBindingCollector = new BindingCollector();
|
fBindingCollector = new BindingCollector();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,8 +182,8 @@ public class BindingClassifier {
|
||||||
/**
|
/**
|
||||||
* Returns the bindings which only require a simple forward declaration.
|
* Returns the bindings which only require a simple forward declaration.
|
||||||
*/
|
*/
|
||||||
public Set<IBinding> getBindingsToDeclare() {
|
public Set<IBinding> getBindingsToForwardDeclare() {
|
||||||
return fBindingsToDeclare;
|
return fBindingsToForwardDeclare;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -306,46 +310,56 @@ public class BindingClassifier {
|
||||||
* or an empty list if no such binding is available.
|
* or an empty list if no such binding is available.
|
||||||
*/
|
*/
|
||||||
private Set<IBinding> getRequiredBindings(IBinding binding) {
|
private Set<IBinding> getRequiredBindings(IBinding binding) {
|
||||||
Set<IBinding> bindings = new HashSet<IBinding>();
|
if (binding instanceof ICPPNamespace)
|
||||||
|
return Collections.emptySet();
|
||||||
|
|
||||||
if (binding instanceof ICPPMember) {
|
Deque<IBinding> queue = new ArrayDeque<>();
|
||||||
// If the binding is a member, get its owning composite type.
|
|
||||||
binding = binding.getOwner();
|
addRequiredBindings(binding, queue);
|
||||||
} else if (binding instanceof IVariable) {
|
|
||||||
|
Set<IBinding> bindings = new HashSet<>();
|
||||||
|
|
||||||
|
while ((binding = queue.poll()) != null) {
|
||||||
|
if (!bindings.add(binding))
|
||||||
|
continue;
|
||||||
if (binding instanceof ICPPSpecialization) {
|
if (binding instanceof ICPPSpecialization) {
|
||||||
bindings.add(((ICPPSpecialization) binding).getSpecializedBinding());
|
ICPPTemplateParameterMap parameterMap = ((ICPPSpecialization) binding).getTemplateParameterMap();
|
||||||
} else {
|
for (Integer position : parameterMap.getAllParameterPositions()) {
|
||||||
bindings.add(binding);
|
ICPPTemplateArgument argument = parameterMap.getArgument(position);
|
||||||
}
|
if (argument != null) {
|
||||||
} else if (binding instanceof IType) {
|
IType type = argument.getTypeValue();
|
||||||
// Resolve the type.
|
// Normally we don't need to define parameters of a template specialization
|
||||||
binding = getTypeBinding((IType) binding);
|
// that were not specified explicitly. __gnu_cxx::hash is an exception from
|
||||||
} else if (binding instanceof ICPPNamespace) {
|
// that rule.
|
||||||
// Namespaces are neither declared nor defined.
|
if (type instanceof IBinding && "hash".equals(((IBinding) type).getName())) { //$NON-NLS-1$
|
||||||
binding = null;
|
IBinding owner = ((IBinding) type).getOwner();
|
||||||
}
|
if (owner instanceof ICPPNamespace && "__gnu_cxx".equals(owner.getName())) //$NON-NLS-1$
|
||||||
|
addRequiredBindings((IBinding) type, queue);
|
||||||
if (binding instanceof ICPPSpecialization) {
|
}
|
||||||
ICPPTemplateParameterMap parameterMap = ((ICPPSpecialization) binding).getTemplateParameterMap();
|
|
||||||
for (Integer position : parameterMap.getAllParameterPositions()) {
|
|
||||||
ICPPTemplateArgument argument = parameterMap.getArgument(position);
|
|
||||||
if (argument != null) {
|
|
||||||
IType type = argument.getTypeValue();
|
|
||||||
// Normally we don't need to define parameters of a template specialization that
|
|
||||||
// were not specified explicitly. __gnu_cxx::hash is an exception from that rule.
|
|
||||||
if (type instanceof IBinding && "hash".equals(((IBinding) type).getName())) { //$NON-NLS-1$
|
|
||||||
IBinding owner = ((IBinding) type).getOwner();
|
|
||||||
if (owner instanceof ICPPNamespace && "__gnu_cxx".equals(owner.getName())) //$NON-NLS-1$
|
|
||||||
bindings.add((IBinding) type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Get the specialized binding - e.g. get the binding for X if the current binding is
|
||||||
|
// for the template specialization X<Y>.
|
||||||
|
addRequiredBindings(((ICPPSpecialization) binding).getSpecializedBinding(), queue);
|
||||||
}
|
}
|
||||||
// Get the specialized binding - e.g. get the binding for X if the current binding is
|
|
||||||
// for the template specialization X<Y>.
|
|
||||||
binding = ((ICPPSpecialization) binding).getSpecializedBinding();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (binding instanceof IProblemBinding) {
|
return bindings;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addRequiredBindings(IBinding binding, Deque<IBinding> newBindings) {
|
||||||
|
if (binding instanceof ICPPMember) {
|
||||||
|
if (binding instanceof ICPPMethod) {
|
||||||
|
newBindings.add(binding); // Include the method in case we need its definition.
|
||||||
|
}
|
||||||
|
// If the binding is a member, get its owning composite type.
|
||||||
|
newBindings.add(binding.getOwner());
|
||||||
|
} else if (binding instanceof IType) {
|
||||||
|
// Remove type qualifiers.
|
||||||
|
IBinding b = getTypeBinding((IType) binding);
|
||||||
|
if (b != null)
|
||||||
|
newBindings.add(b);
|
||||||
|
} else if (binding instanceof IProblemBinding) {
|
||||||
IProblemBinding problemBinding = (IProblemBinding) binding;
|
IProblemBinding problemBinding = (IProblemBinding) binding;
|
||||||
|
|
||||||
IBinding[] candidateBindings = problemBinding.getCandidateBindings();
|
IBinding[] candidateBindings = problemBinding.getCandidateBindings();
|
||||||
|
@ -354,25 +368,19 @@ public class BindingClassifier {
|
||||||
// different candidates are very often defined within the same target file anyway,
|
// different candidates are very often defined within the same target file anyway,
|
||||||
// so it won't affect the list of generated include directives. This therefore
|
// so it won't affect the list of generated include directives. This therefore
|
||||||
// allows us to be a little more fault tolerant here.
|
// allows us to be a little more fault tolerant here.
|
||||||
for (IBinding candidateBinding : candidateBindings) {
|
Collections.addAll(newBindings, candidateBindings);
|
||||||
bindings.add(candidateBinding);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// No candidate bindings available. Check whether this is a macro.
|
// No candidate bindings available. Check whether this is a macro.
|
||||||
try {
|
try {
|
||||||
IIndexMacro[] indexMacros = fContext.getIndex().findMacros(binding.getNameCharArray(),
|
IIndexMacro[] indexMacros =
|
||||||
IndexFilter.ALL, null);
|
fContext.getIndex().findMacros(binding.getNameCharArray(), IndexFilter.ALL, null);
|
||||||
for (IIndexMacro indexMacro : indexMacros) {
|
Collections.addAll(newBindings, indexMacros);
|
||||||
bindings.add(indexMacro);
|
|
||||||
}
|
|
||||||
} catch (CoreException e) {
|
} catch (CoreException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (binding != null) {
|
} else {
|
||||||
bindings.add(binding);
|
newBindings.add(binding);
|
||||||
}
|
}
|
||||||
|
|
||||||
return bindings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void declareType(IType type) {
|
private void declareType(IType type) {
|
||||||
|
@ -404,7 +412,8 @@ public class BindingClassifier {
|
||||||
Collection<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 (fBindingsToForwardDeclare.contains(requiredBinding) ||
|
||||||
|
fBindingsToDefine.contains(requiredBinding)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (fAst.getDefinitionsInAST(requiredBinding).length != 0) {
|
if (fAst.getDefinitionsInAST(requiredBinding).length != 0) {
|
||||||
|
@ -416,7 +425,7 @@ public class BindingClassifier {
|
||||||
|
|
||||||
if (canForwardDeclare(requiredBinding)) {
|
if (canForwardDeclare(requiredBinding)) {
|
||||||
if (requiredBinding == binding) {
|
if (requiredBinding == binding) {
|
||||||
fBindingsToDeclare.add(requiredBinding);
|
fBindingsToForwardDeclare.add(requiredBinding);
|
||||||
} else {
|
} else {
|
||||||
declareBinding(requiredBinding);
|
declareBinding(requiredBinding);
|
||||||
}
|
}
|
||||||
|
@ -493,18 +502,19 @@ public class BindingClassifier {
|
||||||
private void defineBinding(IBinding binding) {
|
private void defineBinding(IBinding binding) {
|
||||||
if (!markAsDefined(binding))
|
if (!markAsDefined(binding))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fAst.getDefinitionsInAST(binding).length != 0)
|
if (fAst.getDefinitionsInAST(binding).length != 0)
|
||||||
return; // Defined locally.
|
return; // Defined locally.
|
||||||
|
|
||||||
Collection<IBinding> requiredBindings = getRequiredBindings(binding);
|
Collection<IBinding> requiredBindings = getRequiredBindings(binding);
|
||||||
for (IBinding requiredBinding : requiredBindings) {
|
for (IBinding requiredBinding : requiredBindings) {
|
||||||
fBindingsToDeclare.remove(requiredBinding);
|
fBindingsToForwardDeclare.remove(requiredBinding);
|
||||||
if (requiredBinding == binding) {
|
if (requiredBinding != binding) {
|
||||||
fBindingsToDefine.add(requiredBinding);
|
if (!markAsDefined(requiredBinding))
|
||||||
} else {
|
continue;
|
||||||
defineBinding(requiredBinding);
|
if (fAst.getDefinitionsInAST(requiredBinding).length != 0)
|
||||||
|
continue; // Defined locally.
|
||||||
}
|
}
|
||||||
|
fBindingsToDefine.add(requiredBinding);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -538,7 +548,7 @@ public class BindingClassifier {
|
||||||
for (ICPPClassType base : bases) {
|
for (ICPPClassType base : bases) {
|
||||||
fProcessedDefinedBindings.add(base);
|
fProcessedDefinedBindings.add(base);
|
||||||
fBindingsToDefine.remove(base);
|
fBindingsToDefine.remove(base);
|
||||||
fBindingsToDeclare.remove(base);
|
fBindingsToForwardDeclare.remove(base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,7 +577,7 @@ public class BindingClassifier {
|
||||||
if (type instanceof ICPPTemplateInstance) {
|
if (type instanceof ICPPTemplateInstance) {
|
||||||
ICPPTemplateInstance instance = (ICPPTemplateInstance) type;
|
ICPPTemplateInstance instance = (ICPPTemplateInstance) type;
|
||||||
IBinding template = instance.getSpecializedBinding();
|
IBinding template = instance.getSpecializedBinding();
|
||||||
if (templatesAllowingIncompleteArgumentType.contains(template.getName())) {
|
if (isTemplateAllowingIncompleteArgumentType(template)) {
|
||||||
ICPPTemplateArgument[] arguments = instance.getTemplateArguments();
|
ICPPTemplateArgument[] arguments = instance.getTemplateArguments();
|
||||||
if (arguments.length != 0) {
|
if (arguments.length != 0) {
|
||||||
IType argumentType = arguments[0].getTypeValue();
|
IType argumentType = arguments[0].getTypeValue();
|
||||||
|
@ -589,6 +599,17 @@ public class BindingClassifier {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isTemplateAllowingIncompleteArgumentType(IBinding binding) {
|
||||||
|
String name = binding.getName();
|
||||||
|
int pos = Arrays.binarySearch(TEMPLATES_ALLOWING_INCOMPLETE_ARGUMENT_TYPE, name);
|
||||||
|
if (pos < 0)
|
||||||
|
return false;
|
||||||
|
IBinding owner = binding.getOwner();
|
||||||
|
if (!(owner instanceof ICPPNamespace))
|
||||||
|
return false;
|
||||||
|
return CharArrayUtils.equals(owner.getNameCharArray(), STD) && owner.getOwner() == null;
|
||||||
|
}
|
||||||
|
|
||||||
private class BindingCollector extends ASTVisitor {
|
private class BindingCollector extends ASTVisitor {
|
||||||
BindingCollector() {
|
BindingCollector() {
|
||||||
super(true);
|
super(true);
|
||||||
|
@ -1297,8 +1318,7 @@ public class BindingClassifier {
|
||||||
!CharArrayUtils.equals(owner.getNameCharArray(), STD) || owner.getOwner() != null) {
|
!CharArrayUtils.equals(owner.getNameCharArray(), STD) || owner.getOwner() != null) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
String templateName = template.getName();
|
if (!isTemplateAllowingIncompleteArgumentType(template))
|
||||||
if (!templatesAllowingIncompleteArgumentType.contains(templateName))
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// For most templates allowing incomplete argument type a full definition of the argument
|
// For most templates allowing incomplete argument type a full definition of the argument
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class IncludeCreationContext extends InclusionContext {
|
||||||
return fSourceContents;
|
return fSourceContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IIndex getIndex() {
|
public final IIndex getIndex() {
|
||||||
return fIndex;
|
return fIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ import org.eclipse.cdt.core.index.IIndexInclude;
|
||||||
import org.eclipse.cdt.core.index.IIndexName;
|
import org.eclipse.cdt.core.index.IIndexName;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.core.parser.Keywords;
|
import org.eclipse.cdt.core.parser.Keywords;
|
||||||
|
import org.eclipse.cdt.core.parser.util.ArrayUtil;
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
|
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
|
||||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||||
import org.eclipse.cdt.ui.CUIPlugin;
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
@ -199,7 +200,7 @@ public class IncludeOrganizer {
|
||||||
// Process the given translation unit with the inclusion resolver.
|
// Process the given translation unit with the inclusion resolver.
|
||||||
BindingClassifier bindingClassifier = new BindingClassifier(fContext);
|
BindingClassifier bindingClassifier = new BindingClassifier(fContext);
|
||||||
bindingClassifier.classifyNodeContents(ast);
|
bindingClassifier.classifyNodeContents(ast);
|
||||||
Set<IBinding> bindingsToDefine = bindingClassifier.getBindingsToDefine();
|
Set<IBinding> bindingsToInclude = bindingClassifier.getBindingsToDefine();
|
||||||
|
|
||||||
IASTPreprocessorIncludeStatement[] existingIncludes = ast.getIncludeDirectives();
|
IASTPreprocessorIncludeStatement[] existingIncludes = ast.getIncludeDirectives();
|
||||||
fContext.addHeadersIncludedPreviously(existingIncludes);
|
fContext.addHeadersIncludedPreviously(existingIncludes);
|
||||||
|
@ -209,7 +210,7 @@ public class IncludeOrganizer {
|
||||||
// bindings which have to be defined.
|
// bindings which have to be defined.
|
||||||
IIndexFileSet reachableHeaders = ast.getIndexFileSet();
|
IIndexFileSet reachableHeaders = ast.getIndexFileSet();
|
||||||
|
|
||||||
List<InclusionRequest> requests = createInclusionRequests(ast, bindingsToDefine, false, reachableHeaders);
|
List<InclusionRequest> requests = createInclusionRequests(ast, bindingsToInclude, false, reachableHeaders);
|
||||||
processInclusionRequests(requests, headerSubstitutor);
|
processInclusionRequests(requests, headerSubstitutor);
|
||||||
|
|
||||||
// Use a map instead of a set to be able to retrieve existing elements using equal elements.
|
// Use a map instead of a set to be able to retrieve existing elements using equal elements.
|
||||||
|
@ -357,7 +358,7 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
IIndexFileSet reachableHeaders = ast.getIndexFileSet();
|
IIndexFileSet reachableHeaders = ast.getIndexFileSet();
|
||||||
Set<IBinding> bindings =
|
Set<IBinding> bindings =
|
||||||
removeBindingsDefinedInIncludedHeaders(ast, classifier.getBindingsToDeclare(), reachableHeaders);
|
removeBindingsDefinedInIncludedHeaders(ast, classifier.getBindingsToForwardDeclare(), reachableHeaders);
|
||||||
for (IBinding binding : bindings) {
|
for (IBinding binding : bindings) {
|
||||||
// Create the text of the forward declaration of this binding.
|
// Create the text of the forward declaration of this binding.
|
||||||
StringBuilder declarationText = new StringBuilder();
|
StringBuilder declarationText = new StringBuilder();
|
||||||
|
@ -748,13 +749,12 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
private Set<IBinding> removeBindingsDefinedInIncludedHeaders(IASTTranslationUnit ast,
|
private Set<IBinding> removeBindingsDefinedInIncludedHeaders(IASTTranslationUnit ast,
|
||||||
Set<IBinding> bindings, IIndexFileSet reachableHeaders) throws CoreException {
|
Set<IBinding> bindings, IIndexFileSet reachableHeaders) throws CoreException {
|
||||||
Set<IBinding> filteredBindings = new HashSet<>(bindings);
|
|
||||||
|
|
||||||
List<InclusionRequest> requests = createInclusionRequests(ast, bindings, true, reachableHeaders);
|
List<InclusionRequest> requests = createInclusionRequests(ast, bindings, true, reachableHeaders);
|
||||||
Set<IPath> allIncludedHeaders = new HashSet<>();
|
Set<IPath> allIncludedHeaders = new HashSet<>();
|
||||||
allIncludedHeaders.addAll(fContext.getHeadersAlreadyIncluded());
|
allIncludedHeaders.addAll(fContext.getHeadersAlreadyIncluded());
|
||||||
allIncludedHeaders.addAll(fContext.getHeadersToInclude());
|
allIncludedHeaders.addAll(fContext.getHeadersToInclude());
|
||||||
|
|
||||||
|
Set<IBinding> filteredBindings = new HashSet<>(bindings);
|
||||||
for (InclusionRequest request : requests) {
|
for (InclusionRequest request : requests) {
|
||||||
if (isSatisfiedByIncludedHeaders(request, allIncludedHeaders))
|
if (isSatisfiedByIncludedHeaders(request, allIncludedHeaders))
|
||||||
filteredBindings.remove(request.getBinding());
|
filteredBindings.remove(request.getBinding());
|
||||||
|
@ -992,12 +992,12 @@ public class IncludeOrganizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<InclusionRequest> createInclusionRequests(IASTTranslationUnit ast,
|
private List<InclusionRequest> createInclusionRequests(IASTTranslationUnit ast,
|
||||||
Set<IBinding> bindingsToDefine, boolean allowDeclarations,
|
Set<IBinding> bindingsToInclude, boolean allowDeclarations,
|
||||||
IIndexFileSet reachableHeaders) throws CoreException {
|
IIndexFileSet reachableHeaders) throws CoreException {
|
||||||
List<InclusionRequest> requests = new ArrayList<InclusionRequest>(bindingsToDefine.size());
|
List<InclusionRequest> requests = new ArrayList<InclusionRequest>(bindingsToInclude.size());
|
||||||
IIndex index = fContext.getIndex();
|
IIndex index = fContext.getIndex();
|
||||||
|
|
||||||
binding_loop: for (IBinding binding : bindingsToDefine) {
|
binding_loop: for (IBinding binding : bindingsToInclude) {
|
||||||
IIndexName[] indexNames;
|
IIndexName[] indexNames;
|
||||||
if (binding instanceof IMacroBinding) {
|
if (binding instanceof IMacroBinding) {
|
||||||
indexNames = IIndexName.EMPTY_ARRAY;
|
indexNames = IIndexName.EMPTY_ARRAY;
|
||||||
|
@ -1012,12 +1012,30 @@ public class IncludeOrganizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (allowDeclarations || binding instanceof IFunction || binding instanceof IVariable) {
|
} else if (allowDeclarations || binding instanceof IVariable) {
|
||||||
// For functions and variables we need to include a declaration.
|
// For a variable we need to include a declaration.
|
||||||
indexNames = index.findDeclarations(binding);
|
indexNames = index.findDeclarations(binding);
|
||||||
|
} else if (binding instanceof ICPPMethod) {
|
||||||
|
// Include the headers containing method definitions except the ones also containing
|
||||||
|
// the definition of the owner class. The headers defining the owner class are taken
|
||||||
|
// care of separately.
|
||||||
|
Set<IIndexFile> declarationFiles = new HashSet<>();
|
||||||
|
IIndexName[] declarations = index.findNames(binding, IIndex.FIND_DECLARATIONS);
|
||||||
|
for (IIndexName declaration : declarations) {
|
||||||
|
IIndexFile file = declaration.getFile();
|
||||||
|
if (file != null) {
|
||||||
|
declarationFiles.add(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
IIndexName[] definitions = index.findDefinitions(binding);
|
||||||
|
indexNames = filterIncludableNotInBlacklistedFiles(definitions, declarationFiles);
|
||||||
} else {
|
} else {
|
||||||
// For all other bindings we need to include the definition.
|
|
||||||
indexNames = index.findDefinitions(binding);
|
indexNames = index.findDefinitions(binding);
|
||||||
|
if (binding instanceof IFunction) {
|
||||||
|
// If a function is defined in a header, include that header.
|
||||||
|
// Otherwise look for declarations.
|
||||||
|
indexNames = filterIncludableNotInBlacklistedFiles(indexNames, Collections.<IIndexFile>emptySet());
|
||||||
|
}
|
||||||
if (indexNames.length == 0) {
|
if (indexNames.length == 0) {
|
||||||
// If we could not find any definitions, there is still a chance that
|
// If we could not find any definitions, there is still a chance that
|
||||||
// a declaration would be sufficient.
|
// a declaration would be sufficient.
|
||||||
|
@ -1035,12 +1053,11 @@ public class IncludeOrganizer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<IIndexFile, IPath> declaringHeaders = new HashMap<IIndexFile, IPath>();
|
Map<IIndexFile, IPath> declaringHeaders = new HashMap<>();
|
||||||
Map<IIndexFile, IPath> reachableDeclaringHeaders = new HashMap<IIndexFile, IPath>();
|
Map<IIndexFile, IPath> reachableDeclaringHeaders = new HashMap<>();
|
||||||
for (IIndexName indexName : indexNames) {
|
for (IIndexName indexName : indexNames) {
|
||||||
IIndexFile indexFile = indexName.getFile();
|
IIndexFile indexFile = indexName.getFile();
|
||||||
if (IncludeUtil.isSource(indexFile, fContext.getProject()) &&
|
if (!canBeIncluded(indexFile)) {
|
||||||
index.findIncludedBy(indexFile, 0).length == 0) {
|
|
||||||
// The target is a source file which isn't included by any other files.
|
// The target is a source file which isn't included by any other files.
|
||||||
// Don't include it.
|
// Don't include it.
|
||||||
continue;
|
continue;
|
||||||
|
@ -1064,6 +1081,23 @@ public class IncludeOrganizer {
|
||||||
return requests;
|
return requests;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IIndexName[] filterIncludableNotInBlacklistedFiles(IIndexName[] names, Set<IIndexFile> blacklist)
|
||||||
|
throws CoreException {
|
||||||
|
IIndexName[] includable = IIndexName.EMPTY_ARRAY;
|
||||||
|
int pos = 0;
|
||||||
|
for (IIndexName name : names) {
|
||||||
|
IIndexFile file = name.getFile();
|
||||||
|
if (file != null && !blacklist.contains(file) && canBeIncluded(file))
|
||||||
|
includable = ArrayUtil.appendAt(includable, pos++, name);
|
||||||
|
}
|
||||||
|
return ArrayUtil.trim(includable, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canBeIncluded(IIndexFile indexFile) throws CoreException {
|
||||||
|
return !IncludeUtil.isSource(indexFile, fContext.getProject()) ||
|
||||||
|
fContext.getIndex().findIncludedBy(indexFile, 0).length != 0;
|
||||||
|
}
|
||||||
|
|
||||||
private String createIncludeDirective(IncludePrototype include, String lineComment) {
|
private String createIncludeDirective(IncludePrototype include, String lineComment) {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
// Unresolved includes are preserved out of caution. Partner include is always preserved.
|
// Unresolved includes are preserved out of caution. Partner include is always preserved.
|
||||||
|
|
Loading…
Add table
Reference in a new issue