1
0
Fork 0
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:
Sergey Prigogin 2014-05-02 10:31:19 -07:00
parent 7e686b6744
commit 9d7a23cde5
17 changed files with 396 additions and 105 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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;

View file

@ -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()]);

View file

@ -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$

View file

@ -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]);

View file

@ -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>

View file

@ -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);

View file

@ -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 {};

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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