mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-23 06:32:10 +02:00
Bug 414692 - Organize Includes has to honor @headername{<header>} in
doxygen comments
This commit is contained in:
parent
7e686b6744
commit
9d7a23cde5
17 changed files with 396 additions and 105 deletions
|
@ -19,13 +19,15 @@ import org.eclipse.cdt.core.parser.ExtendedScannerInfo;
|
||||||
public class TestScannerInfo extends ExtendedScannerInfo {
|
public class TestScannerInfo extends ExtendedScannerInfo {
|
||||||
private static final String[] EMPTY = {};
|
private static final String[] EMPTY = {};
|
||||||
private String[] fIncludes;
|
private String[] fIncludes;
|
||||||
|
private String[] fLocalIncludes;
|
||||||
private String[] fIncludeFiles;
|
private String[] fIncludeFiles;
|
||||||
private String[] fMacroFiles;
|
private String[] fMacroFiles;
|
||||||
private Map<String, String> fDefinedSymbols;
|
private Map<String, String> fDefinedSymbols;
|
||||||
|
|
||||||
public TestScannerInfo(String[] includes, String[] macroFiles, String[] includeFiles,
|
public TestScannerInfo(String[] includes, String[] localIncludes, String[] macroFiles,
|
||||||
Map<String, String> definedSymbols) {
|
String[] includeFiles, Map<String, String> definedSymbols) {
|
||||||
fIncludes= includes;
|
fIncludes= includes;
|
||||||
|
fLocalIncludes= localIncludes;
|
||||||
fIncludeFiles= includeFiles;
|
fIncludeFiles= includeFiles;
|
||||||
fMacroFiles= macroFiles;
|
fMacroFiles= macroFiles;
|
||||||
fDefinedSymbols= definedSymbols;
|
fDefinedSymbols= definedSymbols;
|
||||||
|
@ -42,13 +44,13 @@ public class TestScannerInfo extends ExtendedScannerInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getIncludeFiles() {
|
public String[] getLocalIncludePath() {
|
||||||
return fIncludeFiles == null ? EMPTY: fIncludeFiles;
|
return fLocalIncludes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String[] getLocalIncludePath() {
|
public String[] getIncludeFiles() {
|
||||||
return null;
|
return fIncludeFiles == null ? EMPTY: fIncludeFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,19 +22,20 @@ import org.eclipse.core.resources.IResource;
|
||||||
|
|
||||||
public class TestScannerProvider extends AbstractCExtension implements IScannerInfoProvider {
|
public class TestScannerProvider extends AbstractCExtension implements IScannerInfoProvider {
|
||||||
public static String[] sIncludes;
|
public static String[] sIncludes;
|
||||||
|
public static String[] sLocalIncludes;
|
||||||
public static String[] sIncludeFiles;
|
public static String[] sIncludeFiles;
|
||||||
public static String[] sMacroFiles;
|
public static String[] sMacroFiles;
|
||||||
public static Map<String, String> sDefinedSymbols = new HashMap<>();
|
public static Map<String, String> sDefinedSymbols = new HashMap<>();
|
||||||
public final static String SCANNER_ID = CTestPlugin.PLUGIN_ID + ".TestScanner";
|
public final static String SCANNER_ID = CTestPlugin.PLUGIN_ID + ".TestScanner";
|
||||||
|
|
||||||
public static void clear() {
|
public static void clear() {
|
||||||
sIncludes= sIncludeFiles= sMacroFiles= null;
|
sIncludes= sLocalIncludes= sIncludeFiles= sMacroFiles= null;
|
||||||
sDefinedSymbols.clear();
|
sDefinedSymbols.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IScannerInfo getScannerInformation(IResource resource) {
|
public IScannerInfo getScannerInformation(IResource resource) {
|
||||||
return new TestScannerInfo(sIncludes, sMacroFiles, sIncludeFiles, sDefinedSymbols);
|
return new TestScannerInfo(sIncludes, sLocalIncludes, sMacroFiles, sIncludeFiles, sDefinedSymbols);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -107,6 +107,23 @@ public interface IIndexFile extends IFileNomination {
|
||||||
*/
|
*/
|
||||||
int getLinkageID() throws CoreException;
|
int getLinkageID() throws CoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the replacement header obtained from <code>@headername{header}</code> or
|
||||||
|
* from {@code IWYU pragma: private, include "header"}. Returns an empty string if the file
|
||||||
|
* contained {@code IWYU pragma: private} without a replacement header. Returns {@code null} if
|
||||||
|
* the file does not contain <code>@headername{header}</code> or {@code IWYU pragma: private}.
|
||||||
|
* @since 5.7
|
||||||
|
*/
|
||||||
|
String getReplacementHeader() throws CoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the replacement header.
|
||||||
|
* @param replacementHeader the name of the replacement header, may be {@code null} or an empty
|
||||||
|
* string
|
||||||
|
* @since 5.7
|
||||||
|
*/
|
||||||
|
void setReplacementHeader(String replacementHeader) throws CoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns detailed information about the file. For debugging only.
|
* Returns detailed information about the file. For debugging only.
|
||||||
* @since 5.4
|
* @since 5.4
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
package org.eclipse.cdt.internal.core.index;
|
package org.eclipse.cdt.internal.core.index;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
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.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
@ -314,23 +315,19 @@ public class CIndex implements IIndex {
|
||||||
@Override
|
@Override
|
||||||
public IIndexInclude[] findIncludedBy(IIndexFile file, int depth) throws CoreException {
|
public IIndexInclude[] findIncludedBy(IIndexFile file, int depth) throws CoreException {
|
||||||
List<IIndexInclude> result= new ArrayList<>();
|
List<IIndexInclude> result= new ArrayList<>();
|
||||||
findIncludedBy(file.getLinkageID(), Collections.singletonList(file), result, depth,
|
Collection<IIndexFile> in = Collections.singletonList(file);
|
||||||
new HashSet<FileContentKey>());
|
Set<FileContentKey> handled = new HashSet<>();
|
||||||
return result.toArray(new IIndexInclude[result.size()]);
|
while (true) {
|
||||||
}
|
Collection<IIndexFile> nextLevel= depth != 0 ? new ArrayDeque<IIndexFile>() : null;
|
||||||
|
for (IIndexFile indexFile : in) {
|
||||||
public void findIncludedBy(int linkageID, List<IIndexFile> in, List<IIndexInclude> out, int depth,
|
IIndexFragmentFile file1 = (IIndexFragmentFile) indexFile;
|
||||||
HashSet<FileContentKey> handled) throws CoreException {
|
|
||||||
List<IIndexFile> nextLevel= depth != 0 ? new LinkedList<IIndexFile>() : null;
|
|
||||||
for (IIndexFile iIndexFile : in) {
|
|
||||||
IIndexFragmentFile file = (IIndexFragmentFile) iIndexFile;
|
|
||||||
for (IIndexFragment fragment : fFragments) {
|
for (IIndexFragment fragment : fFragments) {
|
||||||
IIndexInclude[] includedBy= fragment.findIncludedBy(file);
|
IIndexInclude[] includedBy= fragment.findIncludedBy(file1);
|
||||||
for (IIndexInclude include : includedBy) {
|
for (IIndexInclude include : includedBy) {
|
||||||
final IIndexFile includer = include.getIncludedBy();
|
final IIndexFile includer = include.getIncludedBy();
|
||||||
FileContentKey key= new FileContentKey(linkageID, includer.getLocation(), includer.getSignificantMacros());
|
FileContentKey key= new FileContentKey(file.getLinkageID(), includer.getLocation(), includer.getSignificantMacros());
|
||||||
if (handled.add(key)) {
|
if (handled.add(key)) {
|
||||||
out.add(include);
|
result.add(include);
|
||||||
if (nextLevel != null) {
|
if (nextLevel != null) {
|
||||||
nextLevel.add(includer);
|
nextLevel.add(includer);
|
||||||
}
|
}
|
||||||
|
@ -339,12 +336,14 @@ public class CIndex implements IIndex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextLevel == null || nextLevel.isEmpty()) {
|
if (nextLevel == null || nextLevel.isEmpty()) {
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
if (depth > 0) {
|
if (depth > 0) {
|
||||||
depth--;
|
depth--;
|
||||||
}
|
}
|
||||||
findIncludedBy(linkageID, nextLevel, out, depth, handled);
|
in = nextLevel;
|
||||||
|
}
|
||||||
|
return result.toArray(new IIndexInclude[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -355,21 +354,18 @@ public class CIndex implements IIndex {
|
||||||
@Override
|
@Override
|
||||||
public IIndexInclude[] findIncludes(IIndexFile file, int depth) throws CoreException {
|
public IIndexInclude[] findIncludes(IIndexFile file, int depth) throws CoreException {
|
||||||
List<IIndexInclude> result= new ArrayList<>();
|
List<IIndexInclude> result= new ArrayList<>();
|
||||||
findIncludes(Collections.singletonList(file), result, depth, new HashSet<>());
|
Collection<IIndexFile> in = Collections.singletonList(file);
|
||||||
return result.toArray(new IIndexInclude[result.size()]);
|
Set<Object> handled = new HashSet<>();
|
||||||
}
|
while (true) {
|
||||||
|
Collection<IIndexFile> nextLevel= depth != 0 ? new ArrayDeque<IIndexFile>() : null;
|
||||||
private void findIncludes(List<IIndexFile> in, List<IIndexInclude> out, int depth,
|
for (IIndexFile indexFile : in) {
|
||||||
HashSet<Object> handled) throws CoreException {
|
IIndexFragmentFile file1 = (IIndexFragmentFile) indexFile;
|
||||||
List<IIndexFile> nextLevel= depth != 0 ? new LinkedList<IIndexFile>() : null;
|
IIndexInclude[] includes= file1.getIncludes();
|
||||||
for (IIndexFile iIndexFile : in) {
|
|
||||||
IIndexFragmentFile file = (IIndexFragmentFile) iIndexFile;
|
|
||||||
IIndexInclude[] includes= file.getIncludes();
|
|
||||||
for (IIndexInclude include : includes) {
|
for (IIndexInclude include : includes) {
|
||||||
IIndexFileLocation target= include.getIncludesLocation();
|
IIndexFileLocation target= include.getIncludesLocation();
|
||||||
Object key= target != null ? (Object) target : include.getFullName();
|
Object key= target != null ? (Object) target : include.getFullName();
|
||||||
if (handled.add(key)) {
|
if (handled.add(key)) {
|
||||||
out.add(include);
|
result.add(include);
|
||||||
if (nextLevel != null) {
|
if (nextLevel != null) {
|
||||||
IIndexFile includedByFile= resolveInclude(include);
|
IIndexFile includedByFile= resolveInclude(include);
|
||||||
if (includedByFile != null) {
|
if (includedByFile != null) {
|
||||||
|
@ -380,12 +376,14 @@ public class CIndex implements IIndex {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextLevel == null || nextLevel.isEmpty()) {
|
if (nextLevel == null || nextLevel.isEmpty()) {
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
if (depth > 0) {
|
if (depth > 0) {
|
||||||
depth--;
|
depth--;
|
||||||
}
|
}
|
||||||
findIncludes(nextLevel, out, depth, handled);
|
in = nextLevel;
|
||||||
|
}
|
||||||
|
return result.toArray(new IIndexInclude[result.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -398,7 +396,7 @@ public class CIndex implements IIndex {
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (i < fFragments.length) {
|
if (i < fFragments.length) {
|
||||||
// rollback
|
// Rollback.
|
||||||
fReadLock--;
|
fReadLock--;
|
||||||
while (--i >= 0) {
|
while (--i >= 0) {
|
||||||
fFragments[i].releaseReadLock();
|
fFragments[i].releaseReadLock();
|
||||||
|
|
|
@ -27,10 +27,14 @@ import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.dom.ILinkage;
|
import org.eclipse.cdt.core.dom.ILinkage;
|
||||||
import org.eclipse.cdt.core.dom.IPDOMIndexerTask;
|
import org.eclipse.cdt.core.dom.IPDOMIndexerTask;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTComment;
|
||||||
|
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
|
||||||
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree;
|
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit.IDependencyTree;
|
||||||
|
@ -87,6 +91,8 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
||||||
// Order of constants is important. Stronger update types have to precede the weaker ones.
|
// Order of constants is important. Stronger update types have to precede the weaker ones.
|
||||||
private static enum UpdateKind { REQUIRED_SOURCE, REQUIRED_HEADER, ONE_LINKAGE_HEADER, OTHER_HEADER }
|
private static enum UpdateKind { REQUIRED_SOURCE, REQUIRED_HEADER, ONE_LINKAGE_HEADER, OTHER_HEADER }
|
||||||
|
|
||||||
|
private static final Pattern HEADERNAME_PATTERN = Pattern.compile("@headername\\{(?<header>[^\\}]+)\\}"); //$NON-NLS-1$
|
||||||
|
|
||||||
private static class LinkageTask {
|
private static class LinkageTask {
|
||||||
final int fLinkageID;
|
final int fLinkageID;
|
||||||
private final Map<IIndexFileLocation, LocationTask> fLocationTasks;
|
private final Map<IIndexFileLocation, LocationTask> fLocationTasks;
|
||||||
|
@ -298,6 +304,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
||||||
private boolean fIndexFilesWithoutConfiguration= true;
|
private boolean fIndexFilesWithoutConfiguration= true;
|
||||||
private boolean fIndexAllHeaderVersions = false;
|
private boolean fIndexAllHeaderVersions = false;
|
||||||
private Set<String> fHeadersToIndexAllVersions = Collections.emptySet();
|
private Set<String> fHeadersToIndexAllVersions = Collections.emptySet();
|
||||||
|
private Pattern fPragmaPrivatePattern;
|
||||||
private List<LinkageTask> fRequestsPerLinkage= new ArrayList<>();
|
private List<LinkageTask> fRequestsPerLinkage= new ArrayList<>();
|
||||||
private Map<IIndexFile, IndexFileContent> fIndexContentCache= new LRUCache<>(500);
|
private Map<IIndexFile, IndexFileContent> fIndexContentCache= new LRUCache<>(500);
|
||||||
private Map<IIndexFileLocation, IIndexFragmentFile[]> fIndexFilesCache= new LRUCache<>(5000);
|
private Map<IIndexFileLocation, IIndexFragmentFile[]> fIndexFilesCache= new LRUCache<>(5000);
|
||||||
|
@ -371,6 +378,10 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
||||||
fHeadersToIndexAllVersions = headers;
|
fHeadersToIndexAllVersions = headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setPragmaPrivatePattern(Pattern pattern) {
|
||||||
|
fPragmaPrivatePattern = pattern;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see IPDOMIndexerTask#acceptUrgentTask(IPDOMIndexerTask)
|
* @see IPDOMIndexerTask#acceptUrgentTask(IPDOMIndexerTask)
|
||||||
*/
|
*/
|
||||||
|
@ -1233,15 +1244,28 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
||||||
// The default processing is handled by the indexer task.
|
// The default processing is handled by the indexer task.
|
||||||
PDOMWriter.Data data = new PDOMWriter.Data(ast, fileKeys, fIndex);
|
PDOMWriter.Data data = new PDOMWriter.Data(ast, fileKeys, fIndex);
|
||||||
int storageLinkageID = process(ast, data);
|
int storageLinkageID = process(ast, data);
|
||||||
if (storageLinkageID != ILinkage.NO_LINKAGE_ID)
|
if (storageLinkageID != ILinkage.NO_LINKAGE_ID) {
|
||||||
addSymbols(data, storageLinkageID, ctx, fTodoTaskUpdater, pm);
|
IASTComment[] comments = ast.getComments();
|
||||||
|
data.fReplacementHeaders = extractReplacementHeaders(comments, pm);
|
||||||
|
|
||||||
|
addSymbols(data, storageLinkageID, ctx, pm);
|
||||||
|
|
||||||
|
// Update task markers.
|
||||||
|
if (fTodoTaskUpdater != null) {
|
||||||
|
Set<IIndexFileLocation> locations= new HashSet<>();
|
||||||
|
for (FileInAST file : data.fSelectedFiles) {
|
||||||
|
locations.add(file.fileContentKey.getLocation());
|
||||||
|
}
|
||||||
|
fTodoTaskUpdater.updateTasks(comments, locations.toArray(new IIndexFileLocation[locations.size()]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Contributed processors now have an opportunity to examine the AST.
|
// Contributed processors now have an opportunity to examine the AST.
|
||||||
for (IPDOMASTProcessor processor : PDOMASTProcessorManager.getProcessors(ast)) {
|
for (IPDOMASTProcessor processor : PDOMASTProcessorManager.getProcessors(ast)) {
|
||||||
data = new PDOMWriter.Data(ast, fileKeys, fIndex);
|
data = new PDOMWriter.Data(ast, fileKeys, fIndex);
|
||||||
storageLinkageID = processor.process(ast, data);
|
storageLinkageID = processor.process(ast, data);
|
||||||
if (storageLinkageID != ILinkage.NO_LINKAGE_ID)
|
if (storageLinkageID != ILinkage.NO_LINKAGE_ID)
|
||||||
addSymbols(data, storageLinkageID, ctx, fTodoTaskUpdater, pm);
|
addSymbols(data, storageLinkageID, ctx, pm);
|
||||||
}
|
}
|
||||||
} catch (CoreException | RuntimeException | Error e) {
|
} catch (CoreException | RuntimeException | Error e) {
|
||||||
// Avoid parsing files again, that caused an exception to be thrown.
|
// Avoid parsing files again, that caused an exception to be thrown.
|
||||||
|
@ -1289,6 +1313,83 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses comments to extract replacement headers from <code>@headername{header}</code> and
|
||||||
|
* {@code IWYU pragma: private}.
|
||||||
|
*
|
||||||
|
* @return replacement headers keyed by file paths
|
||||||
|
*/
|
||||||
|
private Map<String, String> extractReplacementHeaders(IASTComment[] comments, IProgressMonitor pm) {
|
||||||
|
Map<String, String> replacementHeaders = new HashMap<>();
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
IASTFileLocation carryoverLocation = null;
|
||||||
|
for (int i = 0; i < comments.length; i++) {
|
||||||
|
IASTComment comment = comments[i];
|
||||||
|
IASTFileLocation location = comment.getFileLocation();
|
||||||
|
if (location == null)
|
||||||
|
continue;
|
||||||
|
String fileName = location.getFileName();
|
||||||
|
if (replacementHeaders.containsKey(fileName))
|
||||||
|
continue;
|
||||||
|
char[] commentChars = comment.getComment();
|
||||||
|
if (commentChars.length <= 2)
|
||||||
|
continue;
|
||||||
|
if (carryoverLocation == null ||
|
||||||
|
!location.getFileName().equals(carryoverLocation.getFileName()) ||
|
||||||
|
location.getStartingLineNumber() != carryoverLocation.getEndingLineNumber() + 1) {
|
||||||
|
text.delete(0, text.length());
|
||||||
|
}
|
||||||
|
carryoverLocation = null;
|
||||||
|
text.append(commentChars, 2, commentChars.length - 2);
|
||||||
|
// Look for @headername{header}.
|
||||||
|
Matcher matcher = HEADERNAME_PATTERN.matcher(text);
|
||||||
|
if (matcher.find()) {
|
||||||
|
String header = matcher.group("header"); //$NON-NLS-1$
|
||||||
|
if (header == null) {
|
||||||
|
header = ""; //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
// Normalize the header list.
|
||||||
|
header = header.replace(" or ", ",").replace(" ", ""); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
|
||||||
|
}
|
||||||
|
replacementHeaders.put(fileName, header);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fPragmaPrivatePattern != null) {
|
||||||
|
// Look for IWYU pragma: private
|
||||||
|
matcher = fPragmaPrivatePattern.matcher(text);
|
||||||
|
if (matcher.find()) {
|
||||||
|
if (!isWhitespace(text, 0, matcher.start()))
|
||||||
|
continue; // Extraneous text before the pragma.
|
||||||
|
if (isWhitespace(text, matcher.end(), text.length())) {
|
||||||
|
String header = matcher.group("header"); //$NON-NLS-1$
|
||||||
|
if (header == null)
|
||||||
|
header = ""; //$NON-NLS-1$
|
||||||
|
replacementHeaders.put(fileName, header);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Handle the case when a IWYU pragma is split between two comment lines as:
|
||||||
|
// IWYU pragma: private,
|
||||||
|
// include "header"
|
||||||
|
if (text.charAt(matcher.end()) == ',' &&
|
||||||
|
isWhitespace(text, matcher.end() + 1, text.length())) {
|
||||||
|
// Defer processing until the next comment, which will be appended to this
|
||||||
|
// one.
|
||||||
|
carryoverLocation = location;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return replacementHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isWhitespace(CharSequence text, int start, int end) {
|
||||||
|
while (start < end) {
|
||||||
|
if (text.charAt(start++) > ' ')
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public final IndexFileContent getFileContent(int linkageID, IIndexFileLocation ifl,
|
public final IndexFileContent getFileContent(int linkageID, IIndexFileLocation ifl,
|
||||||
IIndexFile file) throws CoreException, DependsOnOutdatedFileException {
|
IIndexFile file) throws CoreException, DependsOnOutdatedFileException {
|
||||||
LinkageTask map = findRequestMap(linkageID);
|
LinkageTask map = findRequestMap(linkageID);
|
||||||
|
|
|
@ -250,10 +250,11 @@ public class PDOM extends PlatformObject implements IPDOM {
|
||||||
*
|
*
|
||||||
* CDT 8.4 development (versions not supported on the 8.3.x branch)
|
* CDT 8.4 development (versions not supported on the 8.3.x branch)
|
||||||
* 170.0 - Unconditionally store arguments of EvalTypeId, bug 430230.
|
* 170.0 - Unconditionally store arguments of EvalTypeId, bug 430230.
|
||||||
|
* 171.0 - Replacement headers for Organize Includes, bug 414692.
|
||||||
*/
|
*/
|
||||||
private static final int MIN_SUPPORTED_VERSION= version(170, 0);
|
private static final int MIN_SUPPORTED_VERSION= version(171, 0);
|
||||||
private static final int MAX_SUPPORTED_VERSION= version(170, Short.MAX_VALUE);
|
private static final int MAX_SUPPORTED_VERSION= version(171, Short.MAX_VALUE);
|
||||||
private static final int DEFAULT_VERSION = version(170, 0);
|
private static final int DEFAULT_VERSION = version(171, 0);
|
||||||
|
|
||||||
private static int version(int major, int minor) {
|
private static int version(int major, int minor) {
|
||||||
return (major << 16) + minor;
|
return (major << 16) + minor;
|
||||||
|
|
|
@ -53,6 +53,7 @@ import org.eclipse.cdt.core.index.IIndexFileLocation;
|
||||||
import org.eclipse.cdt.core.index.IIndexInclude;
|
import org.eclipse.cdt.core.index.IIndexInclude;
|
||||||
import org.eclipse.cdt.core.index.IIndexSymbols;
|
import org.eclipse.cdt.core.index.IIndexSymbols;
|
||||||
import org.eclipse.cdt.core.index.IPDOMASTProcessor;
|
import org.eclipse.cdt.core.index.IPDOMASTProcessor;
|
||||||
|
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
||||||
import org.eclipse.cdt.core.parser.FileContent;
|
import org.eclipse.cdt.core.parser.FileContent;
|
||||||
import org.eclipse.cdt.core.parser.IProblem;
|
import org.eclipse.cdt.core.parser.IProblem;
|
||||||
import org.eclipse.cdt.core.parser.ISignificantMacros;
|
import org.eclipse.cdt.core.parser.ISignificantMacros;
|
||||||
|
@ -77,7 +78,7 @@ import org.eclipse.osgi.util.NLS;
|
||||||
* Abstract class to write information from AST.
|
* Abstract class to write information from AST.
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
*/
|
*/
|
||||||
abstract public class PDOMWriter implements IPDOMASTProcessor {
|
public abstract class PDOMWriter implements IPDOMASTProcessor {
|
||||||
private static final boolean REPORT_UNKNOWN_BUILTINS = false;
|
private static final boolean REPORT_UNKNOWN_BUILTINS = false;
|
||||||
|
|
||||||
public static class FileInAST {
|
public static class FileInAST {
|
||||||
|
@ -146,7 +147,8 @@ abstract public class PDOMWriter implements IPDOMASTProcessor {
|
||||||
final IWritableIndex fIndex;
|
final IWritableIndex fIndex;
|
||||||
final Map<IASTPreprocessorIncludeStatement, Symbols> fSymbolMap = new HashMap<>();
|
final Map<IASTPreprocessorIncludeStatement, Symbols> fSymbolMap = new HashMap<>();
|
||||||
final Set<IASTPreprocessorIncludeStatement> fContextIncludes = new HashSet<>();
|
final Set<IASTPreprocessorIncludeStatement> fContextIncludes = new HashSet<>();
|
||||||
final List<IStatus> fStatuses= new ArrayList<>();
|
final List<IStatus> fStatuses = new ArrayList<>();
|
||||||
|
Map<String, String> fReplacementHeaders; // Replacement headers keyed by file paths.
|
||||||
|
|
||||||
public Data(IASTTranslationUnit ast, FileInAST[] selectedFiles, IWritableIndex index) {
|
public Data(IASTTranslationUnit ast, FileInAST[] selectedFiles, IWritableIndex index) {
|
||||||
fAST= ast;
|
fAST= ast;
|
||||||
|
@ -254,8 +256,7 @@ abstract public class PDOMWriter implements IPDOMASTProcessor {
|
||||||
* the index after your last write operation.
|
* the index after your last write operation.
|
||||||
*/
|
*/
|
||||||
final protected void addSymbols(Data data, int storageLinkageID, FileContext ctx,
|
final protected void addSymbols(Data data, int storageLinkageID, FileContext ctx,
|
||||||
ITodoTaskUpdater taskUpdater, IProgressMonitor pm)
|
IProgressMonitor pm) throws InterruptedException, CoreException {
|
||||||
throws InterruptedException, CoreException {
|
|
||||||
if (data.isEmpty() || storageLinkageID == ILinkage.NO_LINKAGE_ID)
|
if (data.isEmpty() || storageLinkageID == ILinkage.NO_LINKAGE_ID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -271,16 +272,8 @@ abstract public class PDOMWriter implements IPDOMASTProcessor {
|
||||||
// Index update.
|
// Index update.
|
||||||
storeSymbolsInIndex(data, storageLinkageID, ctx, pm);
|
storeSymbolsInIndex(data, storageLinkageID, ctx, pm);
|
||||||
|
|
||||||
// Tasks update.
|
|
||||||
if (taskUpdater != null) {
|
|
||||||
Set<IIndexFileLocation> locations= new HashSet<>();
|
|
||||||
for (FileInAST file : data.fSelectedFiles) {
|
|
||||||
locations.add(file.fileContentKey.getLocation());
|
|
||||||
}
|
|
||||||
taskUpdater.updateTasks(data.fAST.getComments(), locations.toArray(new IIndexFileLocation[locations.size()]));
|
|
||||||
}
|
|
||||||
if (!data.fStatuses.isEmpty()) {
|
if (!data.fStatuses.isEmpty()) {
|
||||||
List<IStatus> stati = data.fStatuses;
|
List<IStatus> statuses = data.fStatuses;
|
||||||
String path= null;
|
String path= null;
|
||||||
if (data.fSelectedFiles.length > 0) {
|
if (data.fSelectedFiles.length > 0) {
|
||||||
path= data.fSelectedFiles[data.fSelectedFiles.length - 1].fileContentKey.getLocation().getURI().getPath();
|
path= data.fSelectedFiles[data.fSelectedFiles.length - 1].fileContentKey.getLocation().getURI().getPath();
|
||||||
|
@ -288,8 +281,8 @@ abstract public class PDOMWriter implements IPDOMASTProcessor {
|
||||||
path= data.fAST.getFilePath().toString();
|
path= data.fAST.getFilePath().toString();
|
||||||
}
|
}
|
||||||
String msg= NLS.bind(Messages.PDOMWriter_errorWhileParsing, path);
|
String msg= NLS.bind(Messages.PDOMWriter_errorWhileParsing, path);
|
||||||
if (stati.size() == 1) {
|
if (statuses.size() == 1) {
|
||||||
IStatus status= stati.get(0);
|
IStatus status= statuses.get(0);
|
||||||
if (msg.equals(status.getMessage())) {
|
if (msg.equals(status.getMessage())) {
|
||||||
throw new CoreException(status);
|
throw new CoreException(status);
|
||||||
}
|
}
|
||||||
|
@ -297,7 +290,7 @@ abstract public class PDOMWriter implements IPDOMASTProcessor {
|
||||||
msg + ':' + status.getMessage(), status.getException()));
|
msg + ':' + status.getMessage(), status.getException()));
|
||||||
}
|
}
|
||||||
throw new CoreException(new MultiStatus(CCorePlugin.PLUGIN_ID, 0,
|
throw new CoreException(new MultiStatus(CCorePlugin.PLUGIN_ID, 0,
|
||||||
stati.toArray(new IStatus[stati.size()]), msg, null));
|
statuses.toArray(new IStatus[statuses.size()]), msg, null));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -583,6 +576,11 @@ abstract public class PDOMWriter implements IPDOMASTProcessor {
|
||||||
boolean pragmaOnce= owner != null ? owner.hasPragmaOnceSemantics() : data.fAST.hasPragmaOnceSemantics();
|
boolean pragmaOnce= owner != null ? owner.hasPragmaOnceSemantics() : data.fAST.hasPragmaOnceSemantics();
|
||||||
file.setPragmaOnceSemantics(pragmaOnce);
|
file.setPragmaOnceSemantics(pragmaOnce);
|
||||||
|
|
||||||
|
String headerKey = IndexLocationFactory.getAbsolutePath(location).toOSString();
|
||||||
|
String replacementHeader = data.fReplacementHeaders.get(headerKey);
|
||||||
|
if (replacementHeader != null)
|
||||||
|
file.setReplacementHeader(replacementHeader);
|
||||||
|
|
||||||
Symbols lists= data.fSymbolMap.get(owner);
|
Symbols lists= data.fSymbolMap.get(owner);
|
||||||
if (lists != null) {
|
if (lists != null) {
|
||||||
IASTPreprocessorStatement[] macros= lists.fMacros.toArray(new IASTPreprocessorStatement[lists.fMacros.size()]);
|
IASTPreprocessorStatement[] macros= lists.fMacros.toArray(new IASTPreprocessorStatement[lists.fMacros.size()]);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2005, 2011 QNX Software Systems and others.
|
* Copyright (c) 2005, 2014 QNX Software Systems and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -79,7 +79,8 @@ public class PDOMFile implements IIndexFragmentFile {
|
||||||
private static final int LAST_USING_DIRECTIVE= SIZE_AND_ENCODING_HASH + 4;
|
private static final int LAST_USING_DIRECTIVE= SIZE_AND_ENCODING_HASH + 4;
|
||||||
private static final int FIRST_MACRO_REFERENCE= LAST_USING_DIRECTIVE + Database.PTR_SIZE;
|
private static final int FIRST_MACRO_REFERENCE= LAST_USING_DIRECTIVE + Database.PTR_SIZE;
|
||||||
private static final int SIGNIFICANT_MACROS= FIRST_MACRO_REFERENCE + Database.PTR_SIZE;
|
private static final int SIGNIFICANT_MACROS= FIRST_MACRO_REFERENCE + Database.PTR_SIZE;
|
||||||
private static final int RECORD_SIZE= SIGNIFICANT_MACROS + Database.PTR_SIZE; // 8*PTR_SIZE + 3+1+8+8+8+4 = 64
|
private static final int REPLACEMENT_HEADER = SIGNIFICANT_MACROS + Database.PTR_SIZE;
|
||||||
|
private static final int RECORD_SIZE= REPLACEMENT_HEADER + Database.PTR_SIZE; // 9*PTR_SIZE + 3+1+8+8+8+4 = 68
|
||||||
|
|
||||||
private static final int FLAG_PRAGMA_ONCE_SEMANTICS = 0x01;
|
private static final int FLAG_PRAGMA_ONCE_SEMANTICS = 0x01;
|
||||||
|
|
||||||
|
@ -214,6 +215,10 @@ public class PDOMFile implements IIndexFragmentFile {
|
||||||
Database db= fLinkage.getDB();
|
Database db= fLinkage.getDB();
|
||||||
db.putByte(record + FLAGS, db.getByte(sourceFile.record + FLAGS));
|
db.putByte(record + FLAGS, db.getByte(sourceFile.record + FLAGS));
|
||||||
|
|
||||||
|
// Transfer the replacement header.
|
||||||
|
db.putRecPtr(record + REPLACEMENT_HEADER, db.getRecPtr(sourceFile.record + REPLACEMENT_HEADER));
|
||||||
|
db.putRecPtr(sourceFile.record + REPLACEMENT_HEADER, 0);
|
||||||
|
|
||||||
// Delete the source file
|
// Delete the source file
|
||||||
sourceFile.delete();
|
sourceFile.delete();
|
||||||
}
|
}
|
||||||
|
@ -600,6 +605,9 @@ public class PDOMFile implements IIndexFragmentFile {
|
||||||
if (locRecord != 0)
|
if (locRecord != 0)
|
||||||
db.getString(locRecord).delete();
|
db.getString(locRecord).delete();
|
||||||
locRecord = db.getRecPtr(record + SIGNIFICANT_MACROS);
|
locRecord = db.getRecPtr(record + SIGNIFICANT_MACROS);
|
||||||
|
if (locRecord != 0)
|
||||||
|
db.getString(locRecord).delete();
|
||||||
|
locRecord = db.getRecPtr(record + REPLACEMENT_HEADER);
|
||||||
if (locRecord != 0)
|
if (locRecord != 0)
|
||||||
db.getString(locRecord).delete();
|
db.getString(locRecord).delete();
|
||||||
|
|
||||||
|
@ -950,6 +958,23 @@ public class PDOMFile implements IIndexFragmentFile {
|
||||||
return fLinkage.getUsingDirectives(this);
|
return fLinkage.getUsingDirectives(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getReplacementHeader() throws CoreException {
|
||||||
|
Database db = fLinkage.getDB();
|
||||||
|
long rec = db.getRecPtr(record + REPLACEMENT_HEADER);
|
||||||
|
return rec == 0 ? null : db.getString(rec).getString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReplacementHeader(String replacementHeader) throws CoreException {
|
||||||
|
Database db = fLinkage.getDB();
|
||||||
|
long oldRecord = db.getRecPtr(record + REPLACEMENT_HEADER);
|
||||||
|
if (oldRecord != 0)
|
||||||
|
db.getString(oldRecord).delete();
|
||||||
|
long newRecord = replacementHeader == null ? 0 : db.newString(replacementHeader).getRecord();
|
||||||
|
db.putRecPtr(record + REPLACEMENT_HEADER, newRecord);
|
||||||
|
}
|
||||||
|
|
||||||
// Required because we cannot reference CCorePlugin in order for StandaloneIndexer to work
|
// Required because we cannot reference CCorePlugin in order for StandaloneIndexer to work
|
||||||
private static IStatus createStatus(String msg) {
|
private static IStatus createStatus(String msg) {
|
||||||
return new Status(IStatus.ERROR, "org.eclipse.cdt.core", msg, null); //$NON-NLS-1$
|
return new Status(IStatus.ERROR, "org.eclipse.cdt.core", msg, null); //$NON-NLS-1$
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2006, 2013 Wind River Systems, Inc. and others.
|
* Copyright (c) 2006, 2014 Wind River Systems, Inc. and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -18,6 +18,8 @@ import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
import org.eclipse.cdt.core.CCorePlugin;
|
import org.eclipse.cdt.core.CCorePlugin;
|
||||||
import org.eclipse.cdt.core.CCorePreferenceConstants;
|
import org.eclipse.cdt.core.CCorePreferenceConstants;
|
||||||
|
@ -103,6 +105,17 @@ public abstract class PDOMIndexerTask extends AbstractIndexerTask implements IPD
|
||||||
}
|
}
|
||||||
setUpdateFlags(IIndexManager.UPDATE_CHECK_TIMESTAMPS | IIndexManager.UPDATE_CHECK_CONTENTS_HASH);
|
setUpdateFlags(IIndexManager.UPDATE_CHECK_TIMESTAMPS | IIndexManager.UPDATE_CHECK_CONTENTS_HASH);
|
||||||
setForceFirstFiles(forceFiles.length);
|
setForceFirstFiles(forceFiles.length);
|
||||||
|
|
||||||
|
ICProject project = getCProject();
|
||||||
|
String privatePattern = CCorePreferenceConstants.getPreference(
|
||||||
|
CCorePreferenceConstants.INCLUDE_PRIVATE_PATTERN, project, null);
|
||||||
|
if (privatePattern != null) {
|
||||||
|
try {
|
||||||
|
setPragmaPrivatePattern(Pattern.compile(privatePattern));
|
||||||
|
} catch (PatternSyntaxException e) {
|
||||||
|
CCorePlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ITranslationUnit[] concat(ITranslationUnit[] added, ITranslationUnit[] changed) {
|
private static ITranslationUnit[] concat(ITranslationUnit[] added, ITranslationUnit[] changed) {
|
||||||
|
@ -128,7 +141,7 @@ public abstract class PDOMIndexerTask extends AbstractIndexerTask implements IPD
|
||||||
if (cmp != 0)
|
if (cmp != 0)
|
||||||
return cmp;
|
return cmp;
|
||||||
}
|
}
|
||||||
int cmp = s1.length-s2.length;
|
int cmp = s1.length - s2.length;
|
||||||
if (cmp != 0)
|
if (cmp != 0)
|
||||||
return cmp;
|
return cmp;
|
||||||
return s1[max].compareTo(s2[max]);
|
return s1[max].compareTo(s2[max]);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2000, 2013 QNX Software Systems and others.
|
* Copyright (c) 2000, 2014 QNX Software Systems and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -181,7 +181,7 @@ public class CCorePreferenceConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Preference key for the regular expression pattern that, when appears in a comment on the same
|
* Preference key for the regular expression pattern that, when appears in a comment on the same
|
||||||
* line as include statement, indicates the the included header file is exported.
|
* line as include statement, indicates that the included header file is exported.
|
||||||
* @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas"
|
* @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas"
|
||||||
*
|
*
|
||||||
* @since 5.5
|
* @since 5.5
|
||||||
|
@ -218,6 +218,22 @@ public class CCorePreferenceConstants {
|
||||||
*/
|
*/
|
||||||
public static final String INCLUDE_END_EXPORTS_PATTERN = "includes.endExportsPattern"; //$NON-NLS-1$
|
public static final String INCLUDE_END_EXPORTS_PATTERN = "includes.endExportsPattern"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for {@link #INCLUDE_PRIVATE_PATTERN}.
|
||||||
|
* @since 5.7
|
||||||
|
*/
|
||||||
|
public static final String DEFAULT_INCLUDE_PRIVATE_PATTERN = "IWYU\\s+(pragma:?\\s+)?private(,\\s+include\\s+(?<header>\\S+))?"; //$NON-NLS-1$
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference key for the regular expression pattern that, when appears in a comment on the same
|
||||||
|
* line as include statement, indicates that the included header file is private and that
|
||||||
|
* another header file should be included instead.
|
||||||
|
* @see "https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas"
|
||||||
|
*
|
||||||
|
* @since 5.7
|
||||||
|
*/
|
||||||
|
public static final String INCLUDE_PRIVATE_PATTERN = "includes.privatePattern"; //$NON-NLS-1$
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A named preference that controls whether the parser should skip trivial expressions in initializer lists.
|
* A named preference that controls whether the parser should skip trivial expressions in initializer lists.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2000, 2013 QNX Software Systems and others.
|
* Copyright (c) 2000, 2014 QNX Software Systems and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -67,6 +67,7 @@ public class CCorePreferenceInitializer extends AbstractPreferenceInitializer {
|
||||||
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_EXPORT_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_EXPORT_PATTERN);
|
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_EXPORT_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_EXPORT_PATTERN);
|
||||||
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_BEGIN_EXPORTS_PATTERN);
|
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_BEGIN_EXPORTS_PATTERN);
|
||||||
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_END_EXPORTS_PATTERN);
|
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_END_EXPORTS_PATTERN);
|
||||||
|
defaultPreferences.put(CCorePreferenceConstants.INCLUDE_PRIVATE_PATTERN, CCorePreferenceConstants.DEFAULT_INCLUDE_PRIVATE_PATTERN);
|
||||||
|
|
||||||
// Scalability defaults.
|
// Scalability defaults.
|
||||||
defaultPreferences.putBoolean(CCorePreferenceConstants.SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS, CCorePreferenceConstants.DEFAULT_SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS);
|
defaultPreferences.putBoolean(CCorePreferenceConstants.SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS, CCorePreferenceConstants.DEFAULT_SCALABILITY_SKIP_TRIVIAL_EXPRESSIONS);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2013 Google, Inc and others.
|
* Copyright (c) 2013, 2014 Google, Inc and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -352,6 +352,57 @@ public class IncludeOrganizerTest extends IncludesTestBase {
|
||||||
assertExpectedResults();
|
assertExpectedResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//dir1/private1.h
|
||||||
|
///** @file dir1/private1.h
|
||||||
|
// * This is an internal header file, included by other library headers.
|
||||||
|
// * Do not attempt to use it directly. @headername{dir1/public1.h}
|
||||||
|
// */
|
||||||
|
//class A {};
|
||||||
|
|
||||||
|
//dir1/public1.h
|
||||||
|
//#include "private1.h"
|
||||||
|
|
||||||
|
//dir1/private2.h
|
||||||
|
//// IWYU pragma: private,
|
||||||
|
//// include "dir1/public2.h"
|
||||||
|
//class B {};
|
||||||
|
|
||||||
|
//dir1/public2.h
|
||||||
|
//#include "private2.h"
|
||||||
|
|
||||||
|
//dir1/private3.h
|
||||||
|
//// IWYU pragma: private
|
||||||
|
//class C {};
|
||||||
|
|
||||||
|
//dir1/public3.h
|
||||||
|
//#include "private3.h"
|
||||||
|
|
||||||
|
//dir2/private4.h
|
||||||
|
//// IWYU pragma: private, include "dir2/public4.h"
|
||||||
|
//class D {};
|
||||||
|
|
||||||
|
//dir2/public4.h
|
||||||
|
//#include "private4.h"
|
||||||
|
|
||||||
|
//dir2/source.cpp
|
||||||
|
//A a;
|
||||||
|
//B b;
|
||||||
|
//C c;
|
||||||
|
//D d;
|
||||||
|
//====================
|
||||||
|
//#include "dir1/public1.h"
|
||||||
|
//#include "dir1/public2.h"
|
||||||
|
//#include "dir1/public3.h"
|
||||||
|
//#include "dir2/private4.h"
|
||||||
|
//
|
||||||
|
//A a;
|
||||||
|
//B b;
|
||||||
|
//C c;
|
||||||
|
//D d;
|
||||||
|
public void testPrivateHeaders() throws Exception {
|
||||||
|
assertExpectedResults();
|
||||||
|
}
|
||||||
|
|
||||||
//h1.h
|
//h1.h
|
||||||
//class A {};
|
//class A {};
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,11 @@ import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.core.resources.IFile;
|
import org.eclipse.core.resources.IFile;
|
||||||
|
import org.eclipse.core.resources.IProject;
|
||||||
import org.eclipse.core.resources.IResource;
|
import org.eclipse.core.resources.IResource;
|
||||||
import org.eclipse.core.runtime.IPath;
|
import org.eclipse.core.runtime.IPath;
|
||||||
import org.eclipse.core.runtime.Path;
|
import org.eclipse.core.runtime.Path;
|
||||||
|
import org.eclipse.core.runtime.QualifiedName;
|
||||||
import org.eclipse.jface.preference.IPreferenceStore;
|
import org.eclipse.jface.preference.IPreferenceStore;
|
||||||
import org.osgi.framework.Bundle;
|
import org.osgi.framework.Bundle;
|
||||||
|
|
||||||
|
@ -31,6 +33,7 @@ import org.eclipse.cdt.core.model.CoreModel;
|
||||||
import org.eclipse.cdt.core.model.ICProject;
|
import org.eclipse.cdt.core.model.ICProject;
|
||||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||||
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
import org.eclipse.cdt.core.testplugin.CProjectHelper;
|
||||||
|
import org.eclipse.cdt.core.testplugin.TestScannerProvider;
|
||||||
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
|
import org.eclipse.cdt.core.testplugin.util.BaseTestCase;
|
||||||
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
import org.eclipse.cdt.core.testplugin.util.TestSourceReader;
|
||||||
import org.eclipse.cdt.ui.CUIPlugin;
|
import org.eclipse.cdt.ui.CUIPlugin;
|
||||||
|
@ -44,6 +47,8 @@ import org.eclipse.cdt.internal.ui.refactoring.includes.IHeaderChooser;
|
||||||
*/
|
*/
|
||||||
public abstract class IncludesTestBase extends BaseTestCase {
|
public abstract class IncludesTestBase extends BaseTestCase {
|
||||||
protected final String LINE_DELIMITER = "\n";
|
protected final String LINE_DELIMITER = "\n";
|
||||||
|
// Same as in CCorePlugin#SCANNER_INFO_PROVIDER2_NAME.
|
||||||
|
private static final String SCANNER_INFO_PROVIDER2_NAME = "ScannerInfoProvider2"; //$NON-NLS-1$
|
||||||
|
|
||||||
protected static class FirstHeaderChooser implements IHeaderChooser {
|
protected static class FirstHeaderChooser implements IHeaderChooser {
|
||||||
@Override
|
@Override
|
||||||
|
@ -78,9 +83,15 @@ public abstract class IncludesTestBase extends BaseTestCase {
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
resetPreferences();
|
resetPreferences();
|
||||||
|
|
||||||
cproject = cpp ?
|
cproject = cpp ?
|
||||||
CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) :
|
CProjectHelper.createCCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER) :
|
||||||
CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER);
|
CProjectHelper.createCProject(getName() + System.currentTimeMillis(), "bin", IPDOMManager.ID_NO_INDEXER);
|
||||||
|
IProject project = cproject.getProject();
|
||||||
|
TestScannerProvider.sLocalIncludes = new String[] { project.getLocation().toOSString() };
|
||||||
|
QualifiedName scannerInfoProviderName = new QualifiedName(CCorePlugin.PLUGIN_ID, SCANNER_INFO_PROVIDER2_NAME);
|
||||||
|
project.setSessionProperty(scannerInfoProviderName, new TestScannerProvider());
|
||||||
|
|
||||||
Bundle bundle = CTestPlugin.getDefault().getBundle();
|
Bundle bundle = CTestPlugin.getDefault().getBundle();
|
||||||
CharSequence[] testData = TestSourceReader.getContentsForTest(bundle, "ui", getClass(), getName(), 0);
|
CharSequence[] testData = TestSourceReader.getContentsForTest(bundle, "ui", getClass(), getName(), 0);
|
||||||
|
|
||||||
|
@ -105,7 +116,7 @@ public abstract class IncludesTestBase extends BaseTestCase {
|
||||||
}
|
}
|
||||||
reader.close();
|
reader.close();
|
||||||
|
|
||||||
sourceFile = TestSourceReader.createFile(cproject.getProject(), new Path(testFile.getName()),
|
sourceFile = TestSourceReader.createFile(project, new Path(testFile.getName()),
|
||||||
testFile.getSource());
|
testFile.getSource());
|
||||||
testFiles.add(testFile);
|
testFiles.add(testFile);
|
||||||
selectedFile = testFile;
|
selectedFile = testFile;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2013 Google, Inc and others.
|
* Copyright (c) 2013, 2014 Google, Inc and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -44,11 +44,13 @@ public class IncludePragmasBlock extends OptionsConfigurationBlock {
|
||||||
private static final Key KEY_EXPORT_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_EXPORT_PATTERN);
|
private static final Key KEY_EXPORT_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_EXPORT_PATTERN);
|
||||||
private static final Key KEY_BEGIN_EXPORTS_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN);
|
private static final Key KEY_BEGIN_EXPORTS_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_BEGIN_EXPORTS_PATTERN);
|
||||||
private static final Key KEY_END_EXPORTS_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN);
|
private static final Key KEY_END_EXPORTS_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_END_EXPORTS_PATTERN);
|
||||||
|
private static final Key KEY_PRIVATE_PATTERN = getCDTCoreKey(CCorePreferenceConstants.INCLUDE_PRIVATE_PATTERN);
|
||||||
|
|
||||||
private static Key[] ALL_KEYS = {
|
private static Key[] ALL_KEYS = {
|
||||||
KEY_EXPORT_PATTERN,
|
KEY_EXPORT_PATTERN,
|
||||||
KEY_BEGIN_EXPORTS_PATTERN,
|
KEY_BEGIN_EXPORTS_PATTERN,
|
||||||
KEY_END_EXPORTS_PATTERN,
|
KEY_END_EXPORTS_PATTERN,
|
||||||
|
KEY_PRIVATE_PATTERN,
|
||||||
};
|
};
|
||||||
private PixelConverter pixelConverter;
|
private PixelConverter pixelConverter;
|
||||||
|
|
||||||
|
@ -81,6 +83,9 @@ public class IncludePragmasBlock extends OptionsConfigurationBlock {
|
||||||
control = addTextField(composite, PreferencesMessages.IncludePragmasBlock_end_exports_pattern,
|
control = addTextField(composite, PreferencesMessages.IncludePragmasBlock_end_exports_pattern,
|
||||||
KEY_END_EXPORTS_PATTERN, 0, pixelConverter.convertWidthInCharsToPixels(40));
|
KEY_END_EXPORTS_PATTERN, 0, pixelConverter.convertWidthInCharsToPixels(40));
|
||||||
LayoutUtil.setHorizontalGrabbing(control, true);
|
LayoutUtil.setHorizontalGrabbing(control, true);
|
||||||
|
control = addTextField(composite, PreferencesMessages.IncludePragmasBlock_end_exports_pattern,
|
||||||
|
KEY_PRIVATE_PATTERN, 0, pixelConverter.convertWidthInCharsToPixels(40));
|
||||||
|
LayoutUtil.setHorizontalGrabbing(control, true);
|
||||||
|
|
||||||
updateControls();
|
updateControls();
|
||||||
return composite;
|
return composite;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2000, 2013 IBM Corporation and others.
|
* Copyright (c) 2000, 2014 IBM Corporation and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -459,6 +459,7 @@ public final class PreferencesMessages extends NLS {
|
||||||
public static String IncludePragmasBlock_export_pattern;
|
public static String IncludePragmasBlock_export_pattern;
|
||||||
public static String IncludePragmasBlock_begin_exports_pattern;
|
public static String IncludePragmasBlock_begin_exports_pattern;
|
||||||
public static String IncludePragmasBlock_end_exports_pattern;
|
public static String IncludePragmasBlock_end_exports_pattern;
|
||||||
|
public static String IncludePragmasBlock_private_pattern;
|
||||||
|
|
||||||
public static String NameStylePreferencePage_title;
|
public static String NameStylePreferencePage_title;
|
||||||
public static String NameStyleBlock_code_node;
|
public static String NameStyleBlock_code_node;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
###############################################################################
|
###############################################################################
|
||||||
# Copyright (c) 2000, 2013 IBM Corporation and others.
|
# Copyright (c) 2000, 2014 IBM Corporation and others.
|
||||||
# All rights reserved. This program and the accompanying materials
|
# All rights reserved. This program and the accompanying materials
|
||||||
# are made available under the terms of the Eclipse Public License v1.0
|
# are made available under the terms of the Eclipse Public License v1.0
|
||||||
# which accompanies this distribution, and is available at
|
# which accompanies this distribution, and is available at
|
||||||
|
@ -514,9 +514,10 @@ IncludeOrderBlock_order_of_includes= O&rder of Include Statements:
|
||||||
IncludePragmasPreferencePage_title= Include Pragmas
|
IncludePragmasPreferencePage_title= Include Pragmas
|
||||||
IncludePragmasBlock_description=Include pragmas are special comments that affect behavior of Organize Includes command. A description of include pragmas can be found in <a href="https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas">IWYU Pragmas</a>. Include patterns can be customized by defining regular expressions matching each of the pragmas.
|
IncludePragmasBlock_description=Include pragmas are special comments that affect behavior of Organize Includes command. A description of include pragmas can be found in <a href="https://code.google.com/p/include-what-you-use/wiki/IWYUPragmas">IWYU Pragmas</a>. Include patterns can be customized by defining regular expressions matching each of the pragmas.
|
||||||
IncludePragmasBlock_link_tooltip=Wiki page describing include-what-you-use pragmas
|
IncludePragmasBlock_link_tooltip=Wiki page describing include-what-you-use pragmas
|
||||||
IncludePragmasBlock_export_pattern= Export:
|
IncludePragmasBlock_export_pattern= &Export:
|
||||||
IncludePragmasBlock_begin_exports_pattern= Begin Exports:
|
IncludePragmasBlock_begin_exports_pattern= &Begin Exports:
|
||||||
IncludePragmasBlock_end_exports_pattern= End Exports:
|
IncludePragmasBlock_end_exports_pattern= En&d Exports:
|
||||||
|
IncludePragmasBlock_private_pattern= &Private:
|
||||||
|
|
||||||
NameStylePreferencePage_title=Name Style
|
NameStylePreferencePage_title=Name Style
|
||||||
NameStyleBlock_code_node=Code
|
NameStyleBlock_code_node=Code
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Copyright (c) 2012, 2013 Google, Inc and others.
|
* Copyright (c) 2012, 2014 Google, Inc and others.
|
||||||
* All rights reserved. This program and the accompanying materials
|
* All rights reserved. This program and the accompanying materials
|
||||||
* are made available under the terms of the Eclipse Public License v1.0
|
* are made available under the terms of the Eclipse Public License v1.0
|
||||||
* which accompanies this distribution, and is available at
|
* which accompanies this distribution, and is available at
|
||||||
|
@ -25,6 +25,7 @@ import org.eclipse.core.runtime.Platform;
|
||||||
import org.eclipse.core.runtime.preferences.IPreferencesService;
|
import org.eclipse.core.runtime.preferences.IPreferencesService;
|
||||||
import org.eclipse.core.runtime.preferences.IScopeContext;
|
import org.eclipse.core.runtime.preferences.IScopeContext;
|
||||||
|
|
||||||
|
import org.eclipse.cdt.core.index.IIndex;
|
||||||
import org.eclipse.cdt.core.index.IIndexFile;
|
import org.eclipse.cdt.core.index.IIndexFile;
|
||||||
import org.eclipse.cdt.core.index.IIndexInclude;
|
import org.eclipse.cdt.core.index.IIndexInclude;
|
||||||
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
import org.eclipse.cdt.core.index.IndexLocationFactory;
|
||||||
|
@ -54,9 +55,10 @@ public class HeaderSubstitutor {
|
||||||
fIncludeMaps[1].addAllMappings(map.getOptionalSubstitutionMap());
|
fIncludeMaps[1].addAllMappings(map.getOptionalSubstitutionMap());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
addHeaderDerivedMappings();
|
||||||
fIncludeMaps[0].transitivelyClose();
|
fIncludeMaps[0].transitivelyClose();
|
||||||
fIncludeMaps[1].transitivelyClose();
|
fIncludeMaps[1].transitivelyClose();
|
||||||
}
|
|
||||||
|
|
||||||
fSymbolExportMap = new SymbolExportMap();
|
fSymbolExportMap = new SymbolExportMap();
|
||||||
str = preferences.getString(CUIPlugin.PLUGIN_ID,
|
str = preferences.getString(CUIPlugin.PLUGIN_ID,
|
||||||
|
@ -69,6 +71,53 @@ public class HeaderSubstitutor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addHeaderDerivedMappings() {
|
||||||
|
try {
|
||||||
|
for (IIndexFile file : fContext.getIndex().getAllFiles()) {
|
||||||
|
String replacement = file.getReplacementHeader();
|
||||||
|
if (replacement != null) {
|
||||||
|
IPath path = IndexLocationFactory.getAbsolutePath(file.getLocation());
|
||||||
|
if (fContext.getCurrentDirectory().isPrefixOf(path)) {
|
||||||
|
// "IWYU pragma: private" does not affect inclusion from files under
|
||||||
|
// the directory where the header is located.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IncludeInfo includeInfo = fContext.getIncludeForHeaderFile(path);
|
||||||
|
if (includeInfo == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (replacement.isEmpty()) {
|
||||||
|
IIndexInclude[] includedBy = fContext.getIndex().findIncludedBy(file, IIndex.DEPTH_ZERO);
|
||||||
|
for (IIndexInclude include : includedBy) {
|
||||||
|
IPath includer = IndexLocationFactory.getAbsolutePath(include.getIncludedByLocation());
|
||||||
|
IncludeInfo replacementInfo = fContext.getIncludeForHeaderFile(includer);
|
||||||
|
if (replacementInfo != null) {
|
||||||
|
fIncludeMaps[0].addMapping(includeInfo, replacementInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String[] headers = replacement.split(","); //$NON-NLS-1$
|
||||||
|
for (String header : headers) {
|
||||||
|
if (!header.isEmpty()) {
|
||||||
|
char firstChar = header.charAt(0);
|
||||||
|
IncludeInfo replacementInfo;
|
||||||
|
if (firstChar == '"' || firstChar == '<') {
|
||||||
|
replacementInfo = new IncludeInfo(header);
|
||||||
|
} else {
|
||||||
|
replacementInfo = new IncludeInfo(header, includeInfo.isSystem());
|
||||||
|
}
|
||||||
|
fIncludeMaps[0].addMapping(includeInfo, replacementInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (CoreException e) {
|
||||||
|
CUIPlugin.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the header file to be used in an {@code #include} statement given the header file
|
* Selects the header file to be used in an {@code #include} statement given the header file
|
||||||
* that needs to be included. Returns absolute path of the header if it can be uniquely
|
* that needs to be included. Returns absolute path of the header if it can be uniquely
|
||||||
|
|
Loading…
Add table
Reference in a new issue