mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-09-10 03:53:21 +02:00
Bug 45203. Support for symbols exported by multiple headers.
This commit is contained in:
parent
2cb5f8a29a
commit
983f7529a3
12 changed files with 579 additions and 51 deletions
|
@ -41,6 +41,7 @@ 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.ICPPConstructor;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPMethod;
|
||||||
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
|
import org.eclipse.cdt.core.dom.ast.cpp.SemanticQueries;
|
||||||
|
import org.eclipse.cdt.core.parser.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reports a problem if object of a class cannot be created because
|
* Reports a problem if object of a class cannot be created because
|
||||||
|
@ -170,13 +171,7 @@ public class AbstractClassInstantiationChecker extends AbstractIndexAstChecker {
|
||||||
private String resolveName(ICPPBinding binding) {
|
private String resolveName(ICPPBinding binding) {
|
||||||
try {
|
try {
|
||||||
if (binding.isGloballyQualified()) {
|
if (binding.isGloballyQualified()) {
|
||||||
StringBuilder buf = new StringBuilder();
|
return StringUtil.join(binding.getQualifiedName(), "::"); //$NON-NLS-1$
|
||||||
for (String item : binding.getQualifiedName()) {
|
|
||||||
if (buf.length() != 0)
|
|
||||||
buf.append("::"); //$NON-NLS-1$
|
|
||||||
buf.append(item);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
}
|
||||||
} catch (DOMException e) {
|
} catch (DOMException e) {
|
||||||
CodanCheckersActivator.log(e);
|
CodanCheckersActivator.log(e);
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013 Google, Inc 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
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.core.parser.util;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static methods for working with strings.
|
||||||
|
*
|
||||||
|
* @since 5.6
|
||||||
|
*/
|
||||||
|
public class StringUtil {
|
||||||
|
|
||||||
|
private StringUtil() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins strings using the given delimiter.
|
||||||
|
*/
|
||||||
|
public static String join(Iterable<String> strings, String delimiter) {
|
||||||
|
if (strings instanceof Collection) {
|
||||||
|
int size = ((Collection<String>) strings).size();
|
||||||
|
if (size == 1)
|
||||||
|
return strings.iterator().next();
|
||||||
|
if (size == 0)
|
||||||
|
return ""; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (String str : strings) {
|
||||||
|
if (buf.length() != 0)
|
||||||
|
buf.append(delimiter);
|
||||||
|
buf.append(str);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins strings using the given delimiter.
|
||||||
|
*/
|
||||||
|
public static String join(String[] strings, String delimiter) {
|
||||||
|
if (strings.length == 1)
|
||||||
|
return strings[0];
|
||||||
|
if (strings.length == 0)
|
||||||
|
return ""; //$NON-NLS-1$
|
||||||
|
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
for (String str : strings) {
|
||||||
|
if (buf.length() != 0)
|
||||||
|
buf.append(delimiter);
|
||||||
|
buf.append(str);
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,7 @@ import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
import org.eclipse.cdt.core.index.IIndex;
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
import org.eclipse.cdt.core.index.IIndexManager;
|
import org.eclipse.cdt.core.index.IIndexManager;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
|
import org.eclipse.cdt.core.parser.util.StringUtil;
|
||||||
import org.eclipse.cdt.core.testplugin.util.OneSourceMultipleHeadersTestCase;
|
import org.eclipse.cdt.core.testplugin.util.OneSourceMultipleHeadersTestCase;
|
||||||
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
||||||
import org.eclipse.cdt.ui.testplugin.CTestPlugin;
|
import org.eclipse.cdt.ui.testplugin.CTestPlugin;
|
||||||
|
@ -90,23 +91,13 @@ public class BindingClassifierTest extends OneSourceMultipleHeadersTestCase {
|
||||||
List<String> errors = new ArrayList<String>(2);
|
List<String> errors = new ArrayList<String>(2);
|
||||||
if (!missing.isEmpty()) {
|
if (!missing.isEmpty()) {
|
||||||
errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" {0,choice,1#is|1<are} not {2}.",
|
errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" {0,choice,1#is|1<are} not {2}.",
|
||||||
missing.size(), join(missing, "\", \""), verb));
|
missing.size(), StringUtil.join(missing, "\", \""), verb));
|
||||||
}
|
}
|
||||||
if (!extra.isEmpty()) {
|
if (!extra.isEmpty()) {
|
||||||
errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" should not be {2}.",
|
errors.add(MessageFormat.format("{0,choice,1#Binding|1<Bindings} \"{1}\" should not be {2}.",
|
||||||
extra.size(), join(extra, "\", \""), verb));
|
extra.size(), StringUtil.join(extra, "\", \""), verb));
|
||||||
}
|
}
|
||||||
fail(join(errors, " "));
|
fail(StringUtil.join(errors, " "));
|
||||||
}
|
|
||||||
|
|
||||||
private String join(Iterable<String> strings, String delimiter) {
|
|
||||||
StringBuilder buf = new StringBuilder();
|
|
||||||
for (String str : strings) {
|
|
||||||
if (buf.length() != 0)
|
|
||||||
buf.append(delimiter);
|
|
||||||
buf.append(str);
|
|
||||||
}
|
|
||||||
return buf.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// class A;
|
// class A;
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.ui.tests.refactoring.includes;
|
package org.eclipse.cdt.ui.tests.refactoring.includes;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import junit.framework.Test;
|
import junit.framework.Test;
|
||||||
|
@ -26,6 +27,7 @@ import org.eclipse.cdt.ui.PreferenceConstants;
|
||||||
import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser;
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser;
|
||||||
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeOrganizer;
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludeOrganizer;
|
||||||
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences.UnusedStatementDisposition;
|
import org.eclipse.cdt.internal.ui.refactoring.includes.IncludePreferences.UnusedStatementDisposition;
|
||||||
|
import org.eclipse.cdt.internal.ui.refactoring.includes.SymbolExportMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link IncludeOrganizer}.
|
* Tests for {@link IncludeOrganizer}.
|
||||||
|
@ -357,4 +359,34 @@ public class IncludeOrganizerTest extends IncludesTestBase {
|
||||||
UnusedStatementDisposition.REMOVE.toString());
|
UnusedStatementDisposition.REMOVE.toString());
|
||||||
assertExpectedResults();
|
assertExpectedResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//string.h
|
||||||
|
//#include "stddef.h"
|
||||||
|
//extern char* strchr(char* s, int c);
|
||||||
|
|
||||||
|
//stddef.h
|
||||||
|
//#define NULL 0
|
||||||
|
|
||||||
|
//source.cpp
|
||||||
|
//#include "stddef.h"
|
||||||
|
//char* test() {
|
||||||
|
// int* p = NULL;
|
||||||
|
// return strchr("aaa", '*');
|
||||||
|
//}
|
||||||
|
//====================
|
||||||
|
//#include "string.h"
|
||||||
|
//
|
||||||
|
//char* test() {
|
||||||
|
// int* p = NULL;
|
||||||
|
// return strchr("aaa", '*');
|
||||||
|
//}
|
||||||
|
public void testExportedSymbol() throws Exception {
|
||||||
|
IPreferenceStore preferenceStore = getPreferenceStore();
|
||||||
|
preferenceStore.setValue(PreferenceConstants.INCLUDES_UNUSED_STATEMENTS_DISPOSITION,
|
||||||
|
UnusedStatementDisposition.REMOVE.toString());
|
||||||
|
SymbolExportMap symbolExportMap = new SymbolExportMap(new String[] { "NULL", "string.h" });
|
||||||
|
preferenceStore.setValue(PreferenceConstants.INCLUDES_SYMBOL_EXPORTING_HEADERS,
|
||||||
|
SymbolExportMap.serializeMaps(Collections.singletonList(symbolExportMap)));
|
||||||
|
assertExpectedResults();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,119 @@ import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class GCCHeaderSubstitutionMaps {
|
public class GCCHeaderSubstitutionMaps {
|
||||||
|
@SuppressWarnings("nls")
|
||||||
|
private static final String[] symbolExportMap = new String[] {
|
||||||
|
"EOF", "<stdio.h>",
|
||||||
|
"EOF", "<libio.h>",
|
||||||
|
"NULL", "<stddef.h>",
|
||||||
|
"NULL", "<cstddef>",
|
||||||
|
"NULL", "<cstdio>",
|
||||||
|
"NULL", "<cstdlib>",
|
||||||
|
"NULL", "<cstring>",
|
||||||
|
"NULL", "<ctime>",
|
||||||
|
"NULL", "<cwchar>",
|
||||||
|
"NULL", "<string>",
|
||||||
|
"NULL", "<locale.h>",
|
||||||
|
"NULL", "<stdio.h>",
|
||||||
|
"NULL", "<stdlib.h>",
|
||||||
|
"NULL", "<string.h>",
|
||||||
|
"NULL", "<time.h>",
|
||||||
|
"NULL", "<wchar.h>",
|
||||||
|
"blkcnt_t", "<sys/stat.h>",
|
||||||
|
"blkcnt_t", "<sys/types.h>",
|
||||||
|
"blksize_t", "<sys/types.h>",
|
||||||
|
"blksize_t", "<sys/stat.h>",
|
||||||
|
"calloc", "<stdlib.h>",
|
||||||
|
"daddr_t", "<sys/types.h>",
|
||||||
|
"daddr_t", "<rpc/types.h>",
|
||||||
|
"dev_t", "<sys/types.h>",
|
||||||
|
"dev_t", "<sys/stat.h>",
|
||||||
|
"error_t", "<errno.h>",
|
||||||
|
"error_t", "<argp.h>",
|
||||||
|
"error_t", "<argz.h>",
|
||||||
|
"free", "<stdlib.h>",
|
||||||
|
"fsblkcnt_t", "<sys/types.h>",
|
||||||
|
"fsblkcnt_t", "<sys/statvfs.h>",
|
||||||
|
"fsfilcnt_t", "<sys/types.h>",
|
||||||
|
"fsfilcnt_t", "<sys/statvfs.h>",
|
||||||
|
"gid_t", "<sys/types.h>",
|
||||||
|
"gid_t", "<grp.h>",
|
||||||
|
"gid_t", "<pwd.h>",
|
||||||
|
"gid_t", "<stropts.h>",
|
||||||
|
"gid_t", "<sys/ipc.h>",
|
||||||
|
"gid_t", "<sys/stat.h>",
|
||||||
|
"gid_t", "<unistd.h>",
|
||||||
|
"id_t", "<sys/types.h>",
|
||||||
|
"id_t", "<sys/resource.h>",
|
||||||
|
"ino64_t", "<sys/types.h>",
|
||||||
|
"ino64_t", "<dirent.h>",
|
||||||
|
"ino_t", "<sys/types.h>",
|
||||||
|
"ino_t", "<dirent.h>",
|
||||||
|
"ino_t", "<sys/stat.h>",
|
||||||
|
"int8_t", "<sys/types.h>",
|
||||||
|
"int8_t", "<stdint.h>",
|
||||||
|
"intptr_t", "<stdint.h>",
|
||||||
|
"intptr_t", "<unistd.h>",
|
||||||
|
"key_t", "<sys/types.h>",
|
||||||
|
"key_t", "<sys/ipc.h>",
|
||||||
|
"malloc", "<stdlib.h>",
|
||||||
|
"mode_t", "<sys/types.h>",
|
||||||
|
"mode_t", "<sys/stat.h>",
|
||||||
|
"mode_t", "<sys/ipc.h>",
|
||||||
|
"mode_t", "<sys/mman.h>",
|
||||||
|
"nlink_t", "<sys/types.h>",
|
||||||
|
"nlink_t", "<sys/stat.h>",
|
||||||
|
"off64_t", "<sys/types.h>",
|
||||||
|
"off64_t", "<unistd.h>",
|
||||||
|
"off_t", "<sys/types.h>",
|
||||||
|
"off_t", "<unistd.h>",
|
||||||
|
"off_t", "<sys/stat.h>",
|
||||||
|
"off_t", "<sys/mman.h>",
|
||||||
|
"pid_t", "<sys/types.h>",
|
||||||
|
"pid_t", "<unistd.h>",
|
||||||
|
"pid_t", "<signal.h>",
|
||||||
|
"pid_t", "<sys/msg.h>",
|
||||||
|
"pid_t", "<sys/shm.h>",
|
||||||
|
"pid_t", "<termios.h>",
|
||||||
|
"pid_t", "<time.h>",
|
||||||
|
"pid_t", "<utmpx.h>",
|
||||||
|
"realloc", "<stdlib.h>",
|
||||||
|
"sigset_t", "<signal.h>",
|
||||||
|
"sigset_t", "<sys/epoll.h>",
|
||||||
|
"sigset_t", "<sys/select.h>",
|
||||||
|
"size_t", "<stddef.h>",
|
||||||
|
"socklen_t", "<bits/socket.h>",
|
||||||
|
"socklen_t", "<unistd.h>",
|
||||||
|
"socklen_t", "<arpa/inet.h>",
|
||||||
|
"ssize_t", "<sys/types.h>",
|
||||||
|
"ssize_t", "<unistd.h>",
|
||||||
|
"ssize_t", "<monetary.h>",
|
||||||
|
"ssize_t", "<sys/msg.h>",
|
||||||
|
"std::allocator", "<memory>",
|
||||||
|
"std::allocator", "<string>",
|
||||||
|
"std::allocator", "<vector>",
|
||||||
|
"std::allocator", "<map>",
|
||||||
|
"std::allocator", "<set>",
|
||||||
|
"std::char_traits", "<string>",
|
||||||
|
"std::char_traits", "<ostream>",
|
||||||
|
"std::char_traits", "<istream>",
|
||||||
|
"suseconds_t", "<sys/types.h>",
|
||||||
|
"suseconds_t", "<sys/time.h>",
|
||||||
|
"suseconds_t", "<sys/select.h>",
|
||||||
|
"u_char", "<sys/types.h>",
|
||||||
|
"u_char", "<rpc/types.h>",
|
||||||
|
"uid_t", "<sys/types.h>",
|
||||||
|
"uid_t", "<unistd.h>",
|
||||||
|
"uid_t", "<pwd.h>",
|
||||||
|
"uid_t", "<signal.h>",
|
||||||
|
"uid_t", "<stropts.h>",
|
||||||
|
"uid_t", "<sys/ipc.h>",
|
||||||
|
"uid_t", "<sys/stat.h>",
|
||||||
|
"useconds_t", "<sys/types.h>",
|
||||||
|
"useconds_t", "<unistd.h>",
|
||||||
|
"va_list", "<stdarg.h>",
|
||||||
|
};
|
||||||
|
|
||||||
@SuppressWarnings("nls")
|
@SuppressWarnings("nls")
|
||||||
private static final String[] cIncludeMap = new String[] {
|
private static final String[] cIncludeMap = new String[] {
|
||||||
"<asm/errno-base.h>", "<errno.h>",
|
"<asm/errno-base.h>", "<errno.h>",
|
||||||
|
@ -365,4 +478,8 @@ public class GCCHeaderSubstitutionMaps {
|
||||||
new IncludeMap(false, cppIncludeMapWeak)),
|
new IncludeMap(false, cppIncludeMapWeak)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SymbolExportMap getSymbolExportMap() {
|
||||||
|
return new SymbolExportMap(symbolExportMap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,20 @@ public class HeaderSubstitutionMap {
|
||||||
return fromMemento(memento);
|
return fromMemento(memento);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String serializeMaps(List<HeaderSubstitutionMap> maps) {
|
||||||
|
XMLMemento memento = XMLMemento.createWriteRoot(TAG_HEADER_SUBSTITUTION_MAPS);
|
||||||
|
for (HeaderSubstitutionMap element : maps) {
|
||||||
|
element.saveToMemento(memento.createChild(TAG_HEADER_SUBSTITUTION_MAP));
|
||||||
|
}
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
try {
|
||||||
|
memento.save(writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
CUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
public static List<HeaderSubstitutionMap> deserializeMaps(String str) {
|
public static List<HeaderSubstitutionMap> deserializeMaps(String str) {
|
||||||
StringReader reader = new StringReader(str);
|
StringReader reader = new StringReader(str);
|
||||||
XMLMemento memento;
|
XMLMemento memento;
|
||||||
|
@ -153,20 +167,6 @@ public class HeaderSubstitutionMap {
|
||||||
return maps;
|
return maps;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String serializeMaps(List<HeaderSubstitutionMap> maps) {
|
|
||||||
XMLMemento memento = XMLMemento.createWriteRoot(TAG_HEADER_SUBSTITUTION_MAPS);
|
|
||||||
for (HeaderSubstitutionMap element : maps) {
|
|
||||||
element.saveToMemento(memento.createChild(TAG_HEADER_SUBSTITUTION_MAP));
|
|
||||||
}
|
|
||||||
StringWriter writer = new StringWriter();
|
|
||||||
try {
|
|
||||||
memento.save(writer);
|
|
||||||
} catch (IOException e) {
|
|
||||||
CUIPlugin.log(e);
|
|
||||||
}
|
|
||||||
return writer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IncludeMap getUnconditionalSubstitutionMap() {
|
public IncludeMap getUnconditionalSubstitutionMap() {
|
||||||
return unconditionalSubstitutionMap;
|
return unconditionalSubstitutionMap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -35,23 +36,34 @@ import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||||
public class HeaderSubstitutor {
|
public class HeaderSubstitutor {
|
||||||
private final InclusionContext fContext;
|
private final InclusionContext fContext;
|
||||||
private IncludeMap[] fIncludeMaps;
|
private IncludeMap[] fIncludeMaps;
|
||||||
|
private SymbolExportMap fSymbolExportMap;
|
||||||
|
|
||||||
public HeaderSubstitutor(InclusionContext context) {
|
public HeaderSubstitutor(InclusionContext context) {
|
||||||
fContext = context;
|
fContext = context;
|
||||||
fIncludeMaps = new IncludeMap[] { new IncludeMap(true), new IncludeMap(false) };
|
fIncludeMaps = new IncludeMap[] { new IncludeMap(true), new IncludeMap(false) };
|
||||||
IPreferencesService preferences = Platform.getPreferencesService();
|
IPreferencesService preferences = Platform.getPreferencesService();
|
||||||
IScopeContext[] scopes = PreferenceConstants.getPreferenceScopes(context.getProject());
|
IScopeContext[] scopes = PreferenceConstants.getPreferenceScopes(context.getProject());
|
||||||
String str = preferences.getString(CUIPlugin.PLUGIN_ID,
|
String str = preferences.getString(CUIPlugin.PLUGIN_ID,
|
||||||
PreferenceConstants.INCLUDES_HEADER_SUBSTITUTION, null, scopes);
|
PreferenceConstants.INCLUDES_HEADER_SUBSTITUTION, null, scopes);
|
||||||
if (str != null) {
|
if (str != null) {
|
||||||
List<HeaderSubstitutionMap> maps = HeaderSubstitutionMap.deserializeMaps(str);
|
List<HeaderSubstitutionMap> maps = HeaderSubstitutionMap.deserializeMaps(str);
|
||||||
for (HeaderSubstitutionMap map : maps) {
|
for (HeaderSubstitutionMap map : maps) {
|
||||||
if (!map.isCppOnly() || fContext.isCXXLanguage()) {
|
if (!map.isCppOnly() || fContext.isCXXLanguage()) {
|
||||||
fIncludeMaps[0].addAllMappings(map.getUnconditionalSubstitutionMap());
|
fIncludeMaps[0].addAllMappings(map.getUnconditionalSubstitutionMap());
|
||||||
fIncludeMaps[1].addAllMappings(map.getOptionalSubstitutionMap());
|
fIncludeMaps[1].addAllMappings(map.getOptionalSubstitutionMap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fSymbolExportMap = new SymbolExportMap();
|
||||||
|
str = preferences.getString(CUIPlugin.PLUGIN_ID,
|
||||||
|
PreferenceConstants.INCLUDES_SYMBOL_EXPORTING_HEADERS, null, scopes);
|
||||||
|
if (str != null) {
|
||||||
|
List<SymbolExportMap> maps = SymbolExportMap.deserializeMaps(str);
|
||||||
|
for (SymbolExportMap map : maps) {
|
||||||
|
fSymbolExportMap.addAllMappings(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,7 +104,7 @@ public class HeaderSubstitutor {
|
||||||
IncludeInfo includeInfo = fContext.getIncludeForHeaderFile(path);
|
IncludeInfo includeInfo = fContext.getIncludeForHeaderFile(path);
|
||||||
if (includeInfo == null)
|
if (includeInfo == null)
|
||||||
return path;
|
return path;
|
||||||
// TODO(sprigogin): Take symbolIncludeMap into account.
|
// TODO(sprigogin): Take fSymbolExportMap into account.
|
||||||
List<IncludeInfo> candidates = new ArrayList<IncludeInfo>();
|
List<IncludeInfo> candidates = new ArrayList<IncludeInfo>();
|
||||||
candidates.add(includeInfo);
|
candidates.add(includeInfo);
|
||||||
IncludeMap[] maps = fIncludeMaps;
|
IncludeMap[] maps = fIncludeMaps;
|
||||||
|
@ -201,6 +213,16 @@ public class HeaderSubstitutor {
|
||||||
return request.getCandidatePaths().iterator().next();
|
return request.getCandidatePaths().iterator().next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the set of headers exporting the given symbol.
|
||||||
|
*/
|
||||||
|
public Set<IncludeInfo> getExportingHeaders(String symbol) {
|
||||||
|
Set<IncludeInfo> headers = fSymbolExportMap.getMapping(symbol);
|
||||||
|
if (headers == null)
|
||||||
|
return Collections.emptySet();
|
||||||
|
return headers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the given URI points within the workspace.
|
* Returns whether the given URI points within the workspace.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -894,7 +894,7 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
// Process headers that are either indirectly included or have unique representatives.
|
// Process headers that are either indirectly included or have unique representatives.
|
||||||
for (InclusionRequest request : requests) {
|
for (InclusionRequest request : requests) {
|
||||||
if (!request.isResolved()) {
|
if (!request.isResolved() && !isExportedBinding(request, headerSubstitutor)) {
|
||||||
List<IPath> candidatePaths = request.getCandidatePaths();
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
Set<IPath> representativeHeaders = new HashSet<IPath>();
|
Set<IPath> representativeHeaders = new HashSet<IPath>();
|
||||||
boolean allRepresented = true;
|
boolean allRepresented = true;
|
||||||
|
@ -929,7 +929,7 @@ public class IncludeOrganizer {
|
||||||
|
|
||||||
// Process remaining unambiguous inclusion requests.
|
// Process remaining unambiguous inclusion requests.
|
||||||
for (InclusionRequest request : requests) {
|
for (InclusionRequest request : requests) {
|
||||||
if (!request.isResolved()) {
|
if (!request.isResolved() && !isExportedBinding(request, headerSubstitutor)) {
|
||||||
List<IPath> candidatePaths = request.getCandidatePaths();
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
if (candidatePaths.size() == 1) {
|
if (candidatePaths.size() == 1) {
|
||||||
IPath path = candidatePaths.iterator().next();
|
IPath path = candidatePaths.iterator().next();
|
||||||
|
@ -956,8 +956,54 @@ public class IncludeOrganizer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve ambiguous inclusion requests.
|
// Resolve ambiguous inclusion requests.
|
||||||
|
for (InclusionRequest request : requests) {
|
||||||
|
if (!request.isResolved() && !isExportedBinding(request, headerSubstitutor)) {
|
||||||
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
|
for (IPath path : candidatePaths) {
|
||||||
|
if (fContext.isIncluded(path)) {
|
||||||
|
request.resolve(path);
|
||||||
|
if (DEBUG_HEADER_SUBSTITUTION) {
|
||||||
|
System.out.println(request.toString() +
|
||||||
|
(fContext.isToBeIncluded(path) ? " (decided earlier)" : " (was previously included)")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!request.isResolved()) {
|
||||||
|
IPath header = fHeaderChooser.chooseHeader(request.getBinding().getName(), candidatePaths);
|
||||||
|
if (header == null)
|
||||||
|
throw new OperationCanceledException();
|
||||||
|
|
||||||
|
request.resolve(header);
|
||||||
|
if (DEBUG_HEADER_SUBSTITUTION) {
|
||||||
|
System.out.println(request.toString() + " (user's choice)"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
if (!fContext.isAlreadyIncluded(header))
|
||||||
|
fContext.addHeaderToInclude(header);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve requests for exported symbols.
|
||||||
for (InclusionRequest request : requests) {
|
for (InclusionRequest request : requests) {
|
||||||
if (!request.isResolved()) {
|
if (!request.isResolved()) {
|
||||||
|
Set<IncludeInfo> exportingHeaders = getExportingHeaders(request, headerSubstitutor);
|
||||||
|
for (IncludeInfo header : exportingHeaders) {
|
||||||
|
IPath path = fContext.resolveInclude(header);
|
||||||
|
if (path != null) {
|
||||||
|
if (fContext.isIncluded(path)) {
|
||||||
|
request.resolve(path);
|
||||||
|
if (DEBUG_HEADER_SUBSTITUTION) {
|
||||||
|
System.out.println(request.toString() +
|
||||||
|
(fContext.isToBeIncluded(path) ? " (decided earlier)" : " (was previously included)")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (request.isResolved())
|
||||||
|
continue;
|
||||||
|
|
||||||
List<IPath> candidatePaths = request.getCandidatePaths();
|
List<IPath> candidatePaths = request.getCandidatePaths();
|
||||||
for (IPath path : candidatePaths) {
|
for (IPath path : candidatePaths) {
|
||||||
if (fContext.isIncluded(path)) {
|
if (fContext.isIncluded(path)) {
|
||||||
|
@ -988,6 +1034,17 @@ public class IncludeOrganizer {
|
||||||
fContext.removeExportedHeaders();
|
fContext.removeExportedHeaders();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isExportedBinding(InclusionRequest request, HeaderSubstitutor headerSubstitutor) {
|
||||||
|
return !getExportingHeaders(request, headerSubstitutor).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Set<IncludeInfo> getExportingHeaders(InclusionRequest request, HeaderSubstitutor headerSubstitutor) {
|
||||||
|
String symbol = request.getBindingQualifiedName();
|
||||||
|
if (symbol == null)
|
||||||
|
return Collections.emptySet();
|
||||||
|
return headerSubstitutor.getExportingHeaders(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
private static IPath getPath(IIndexFileLocation location) {
|
private static IPath getPath(IIndexFileLocation location) {
|
||||||
return IndexLocationFactory.getAbsolutePath(location);
|
return IndexLocationFactory.getAbsolutePath(location);
|
||||||
}
|
}
|
||||||
|
|
|
@ -174,5 +174,7 @@ public class IncludePreferences {
|
||||||
|
|
||||||
store.setDefault(PreferenceConstants.INCLUDES_HEADER_SUBSTITUTION,
|
store.setDefault(PreferenceConstants.INCLUDES_HEADER_SUBSTITUTION,
|
||||||
HeaderSubstitutionMap.serializeMaps(GCCHeaderSubstitutionMaps.getDefaultMaps()));
|
HeaderSubstitutionMap.serializeMaps(GCCHeaderSubstitutionMaps.getDefaultMaps()));
|
||||||
|
store.setDefault(PreferenceConstants.INCLUDES_SYMBOL_EXPORTING_HEADERS,
|
||||||
|
SymbolExportMap.serializeMaps(Collections.singletonList(GCCHeaderSubstitutionMaps.getSymbolExportMap())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,15 +18,22 @@ import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.core.runtime.IPath;
|
import org.eclipse.core.runtime.IPath;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.dom.ast.DOMException;
|
||||||
import org.eclipse.cdt.core.dom.ast.IBinding;
|
import org.eclipse.cdt.core.dom.ast.IBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.cpp.ICPPBinding;
|
||||||
import org.eclipse.cdt.core.index.IIndexFile;
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
|
import org.eclipse.cdt.core.parser.util.StringUtil;
|
||||||
|
|
||||||
class InclusionRequest {
|
class InclusionRequest {
|
||||||
|
private static final String UNINITIALIZED = "uninitialized"; //$NON-NLS-1$
|
||||||
|
|
||||||
private final IBinding fBinding;
|
private final IBinding fBinding;
|
||||||
private final Map<IIndexFile, IPath> fDeclaringFiles;
|
private final Map<IIndexFile, IPath> fDeclaringFiles;
|
||||||
private final boolean fReachable;
|
private final boolean fReachable;
|
||||||
private List<IPath> fCandidatePaths;
|
private List<IPath> fCandidatePaths;
|
||||||
private IPath fResolvedPath;
|
private IPath fResolvedPath;
|
||||||
|
private String fQualifiedName = UNINITIALIZED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param binding the binding that requires inclusion
|
* @param binding the binding that requires inclusion
|
||||||
|
@ -45,7 +52,30 @@ class InclusionRequest {
|
||||||
public IBinding getBinding() {
|
public IBinding getBinding() {
|
||||||
return fBinding;
|
return fBinding;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the qualified name of the binding, or {@code null} if the binding doesn't have
|
||||||
|
* a qualified name.
|
||||||
|
*/
|
||||||
|
public String getBindingQualifiedName() {
|
||||||
|
if (fQualifiedName == UNINITIALIZED) {
|
||||||
|
fQualifiedName = null;
|
||||||
|
if (fBinding instanceof ICPPBinding) {
|
||||||
|
ICPPBinding cppBinding = (ICPPBinding) fBinding;
|
||||||
|
try {
|
||||||
|
if (cppBinding.isGloballyQualified()) {
|
||||||
|
fQualifiedName = StringUtil.join(cppBinding.getQualifiedName(), "::"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
} catch (DOMException e) {
|
||||||
|
// Leave null;
|
||||||
|
}
|
||||||
|
} else if (fBinding instanceof IMacroBinding || fBinding.getOwner() == null) {
|
||||||
|
fQualifiedName = fBinding.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fQualifiedName;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<IIndexFile, IPath> getDeclaringFiles() {
|
public Map<IIndexFile, IPath> getDeclaringFiles() {
|
||||||
return fDeclaringFiles;
|
return fDeclaringFiles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013 Google, Inc 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
|
||||||
|
* http://www.eclipse.org/legal/epl-v10.html
|
||||||
|
*
|
||||||
|
* Contributors:
|
||||||
|
* Sergey Prigogin (Google) - initial API and implementation
|
||||||
|
*******************************************************************************/
|
||||||
|
package org.eclipse.cdt.internal.ui.refactoring.includes;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import java.io.StringWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.ui.IMemento;
|
||||||
|
import org.eclipse.ui.WorkbenchException;
|
||||||
|
import org.eclipse.ui.XMLMemento;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A set of header file substitution rules.
|
||||||
|
*/
|
||||||
|
public class SymbolExportMap {
|
||||||
|
private static final String TAG_SYMBOL_EXPORT_MAPS = "maps"; //$NON-NLS-1$
|
||||||
|
private static final String TAG_SYMBOL_EXPORT_MAP = "map"; //$NON-NLS-1$
|
||||||
|
private static final String TAG_MAPPING = "mapping"; //$NON-NLS-1$
|
||||||
|
private static final String TAG_KEY = "key"; //$NON-NLS-1$
|
||||||
|
private static final String TAG_VALUE = "value"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
private final Map<String, Set<IncludeInfo>> map;
|
||||||
|
|
||||||
|
public SymbolExportMap() {
|
||||||
|
this.map = new HashMap<String, Set<IncludeInfo>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param keysAndValues an array of keys and values: [key1, value1, key2, value2, ...].
|
||||||
|
* Keys and values may be optionally surrounded by double quotes or angle brackets.
|
||||||
|
* Angle brackets indicate a system include.
|
||||||
|
*/
|
||||||
|
public SymbolExportMap(String[] keysAndValues) {
|
||||||
|
if (keysAndValues.length % 2 != 0)
|
||||||
|
throw new IllegalArgumentException("More keys than values"); //$NON-NLS-1$
|
||||||
|
this.map = new HashMap<String, Set<IncludeInfo>>(keysAndValues.length / 2);
|
||||||
|
for (int i = 0; i < keysAndValues.length;) {
|
||||||
|
String key = keysAndValues[i++];
|
||||||
|
addMapping(key, keysAndValues[i++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SymbolExportMap(SymbolExportMap other) {
|
||||||
|
this.map = new HashMap<String, Set<IncludeInfo>>(other.map.size());
|
||||||
|
addAllMappings(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the given symbol is exported by the given header.
|
||||||
|
|
||||||
|
* @param symbol The symbol represented by its fully qualified name.
|
||||||
|
* @param header The header file exporting the symbol.
|
||||||
|
*/
|
||||||
|
protected void addMapping(String symbol, IncludeInfo header) {
|
||||||
|
if (symbol.equals(header))
|
||||||
|
return; // Don't allow mapping to itself.
|
||||||
|
Set<IncludeInfo> list = map.get(symbol);
|
||||||
|
if (list == null) {
|
||||||
|
list = new LinkedHashSet<IncludeInfo>();
|
||||||
|
map.put(symbol, list);
|
||||||
|
}
|
||||||
|
list.add(header);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that the given symbol is exported by the given header.
|
||||||
|
|
||||||
|
* @param symbol The symbol represented by its fully qualified name.
|
||||||
|
* @param header The header file exporting the symbol. The header is represented by an include
|
||||||
|
* name optionally surrounded by double quotes or angle brackets. Angle brackets indicate
|
||||||
|
* a system include.
|
||||||
|
*/
|
||||||
|
public void addMapping(String symbol, String header) {
|
||||||
|
addMapping(symbol, new IncludeInfo(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns header files that should be used instead of the given one.
|
||||||
|
*
|
||||||
|
* @param from The header file to be replaced. A system header has to match exactly.
|
||||||
|
* A non-system header matches both, non-system and system headers.
|
||||||
|
* @return The list of header files ordered by decreasing preference.
|
||||||
|
*/
|
||||||
|
public Set<IncludeInfo> getMapping(String from) {
|
||||||
|
Set<IncludeInfo> list = map.get(from);
|
||||||
|
if (list == null)
|
||||||
|
return Collections.emptySet();
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes exporting headers for a given symbol.
|
||||||
|
*
|
||||||
|
* @param symbol the header file to remove exporting headers for
|
||||||
|
* @return the previous header associated with the symbol, or {@code null} if there were no
|
||||||
|
* exporting headers.
|
||||||
|
*/
|
||||||
|
public Set<IncludeInfo> removeMapping(String symbol) {
|
||||||
|
return map.remove(symbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the map to a memento.
|
||||||
|
*/
|
||||||
|
public void saveToMemento(IMemento memento) {
|
||||||
|
for (Entry<String, Set<IncludeInfo>> entry : map.entrySet()) {
|
||||||
|
String key = entry.getKey().toString();
|
||||||
|
for (IncludeInfo value : entry.getValue()) {
|
||||||
|
IMemento mapping = memento.createChild(TAG_MAPPING);
|
||||||
|
mapping.putString(TAG_KEY, key);
|
||||||
|
mapping.putString(TAG_VALUE, value.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SymbolExportMap fromMemento(IMemento memento) {
|
||||||
|
SymbolExportMap includeMap = new SymbolExportMap();
|
||||||
|
for (IMemento mapping : memento.getChildren(TAG_MAPPING)) {
|
||||||
|
String key = mapping.getString(TAG_KEY);
|
||||||
|
includeMap.addMapping(key, mapping.getString(TAG_VALUE));
|
||||||
|
}
|
||||||
|
return includeMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAllMappings(SymbolExportMap other) {
|
||||||
|
for (Entry<String, Set<IncludeInfo>> entry : other.map.entrySet()) {
|
||||||
|
String source = entry.getKey();
|
||||||
|
Set<IncludeInfo> otherTargets = entry.getValue();
|
||||||
|
Set<IncludeInfo> targets = map.get(source);
|
||||||
|
if (targets == null) {
|
||||||
|
targets = new LinkedHashSet<IncludeInfo>(otherTargets);
|
||||||
|
map.put(source, targets);
|
||||||
|
} else {
|
||||||
|
targets.addAll(otherTargets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** For debugging only. */
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
ArrayList<String> symbols = new ArrayList<String>(map.keySet());
|
||||||
|
Collections.sort(symbols);
|
||||||
|
for (String symbol : symbols) {
|
||||||
|
buf.append('\n');
|
||||||
|
buf.append(symbol);
|
||||||
|
buf.append(" exported by "); //$NON-NLS-1$
|
||||||
|
List<IncludeInfo> targets = new ArrayList<IncludeInfo>(map.get(symbol));
|
||||||
|
for (int i = 0; i < targets.size(); i++) {
|
||||||
|
if (i > 0)
|
||||||
|
buf.append(", "); //$NON-NLS-1$
|
||||||
|
buf.append(targets.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Set<IncludeInfo>> getMap() {
|
||||||
|
return Collections.unmodifiableMap(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String serializeMaps(List<SymbolExportMap> maps) {
|
||||||
|
XMLMemento memento = XMLMemento.createWriteRoot(TAG_SYMBOL_EXPORT_MAPS);
|
||||||
|
for (SymbolExportMap element : maps) {
|
||||||
|
element.saveToMemento(memento.createChild(TAG_SYMBOL_EXPORT_MAP));
|
||||||
|
}
|
||||||
|
StringWriter writer = new StringWriter();
|
||||||
|
try {
|
||||||
|
memento.save(writer);
|
||||||
|
} catch (IOException e) {
|
||||||
|
CUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
return writer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<SymbolExportMap> deserializeMaps(String str) {
|
||||||
|
StringReader reader = new StringReader(str);
|
||||||
|
XMLMemento memento;
|
||||||
|
try {
|
||||||
|
memento = XMLMemento.createReadRoot(reader);
|
||||||
|
} catch (WorkbenchException e) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SymbolExportMap> maps = new ArrayList<SymbolExportMap>();
|
||||||
|
for (IMemento element : memento.getChildren(TAG_SYMBOL_EXPORT_MAP)) {
|
||||||
|
maps.add(fromMemento(element));
|
||||||
|
}
|
||||||
|
return maps;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2064,6 +2064,15 @@ public class PreferenceConstants {
|
||||||
*/
|
*/
|
||||||
public static final String INCLUDES_HEADER_SUBSTITUTION = "organizeIncludes.headerSubstitution"; //$NON-NLS-1$
|
public static final String INCLUDES_HEADER_SUBSTITUTION = "organizeIncludes.headerSubstitution"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symbol exporting rules.
|
||||||
|
* The value of the preference is an XML representation of one or more
|
||||||
|
* {@link org.eclipse.cdt.internal.ui.refactoring.includes.SymbolExportMap}s.
|
||||||
|
*
|
||||||
|
* @since 5.7
|
||||||
|
*/
|
||||||
|
public static final String INCLUDES_SYMBOL_EXPORTING_HEADERS = "organizeIncludes.symbolExportingHeaders"; //$NON-NLS-1$
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Include style for headers closely related to the including file.
|
* Include style for headers closely related to the including file.
|
||||||
* The value of the preference is an XML representation of
|
* The value of the preference is an XML representation of
|
||||||
|
|
Loading…
Add table
Reference in a new issue