/*******************************************************************************
* Copyright (c) 2007, 2015 Wind River Systems, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Markus Schorn - initial API and implementation
* IBM Corporation
* Sergey Prigogin (Google)
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.ILinkage;
import org.eclipse.cdt.core.dom.ast.IASTDeclSpecifier;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorUndefStatement;
import org.eclipse.cdt.core.dom.ast.IASTProblem;
import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.ICompositeType;
import org.eclipse.cdt.core.dom.ast.IEnumeration;
import org.eclipse.cdt.core.dom.ast.IProblemBinding;
import org.eclipse.cdt.core.dom.ast.ITypedef;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTQualifiedName;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTTemplateId;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTUsingDirective;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPClassTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPFunctionTemplate;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespace;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPNamespaceAlias;
import org.eclipse.cdt.core.dom.ast.cpp.ICPPTemplateParameter;
import org.eclipse.cdt.core.index.IIndexFile;
import org.eclipse.cdt.core.index.IIndexFileLocation;
import org.eclipse.cdt.core.index.IIndexInclude;
import org.eclipse.cdt.core.index.IIndexSymbols;
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.IProblem;
import org.eclipse.cdt.core.parser.ISignificantMacros;
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
import org.eclipse.cdt.internal.core.dom.parser.ASTInternal;
import org.eclipse.cdt.internal.core.dom.parser.cpp.ICPPUnknownBinding;
import org.eclipse.cdt.internal.core.index.FileContentKey;
import org.eclipse.cdt.internal.core.index.IIndexFragmentFile;
import org.eclipse.cdt.internal.core.index.IWritableIndex;
import org.eclipse.cdt.internal.core.index.IWritableIndex.IncludeInformation;
import org.eclipse.cdt.internal.core.parser.scanner.LocationMap;
import org.eclipse.cdt.internal.core.pdom.dom.PDOMASTAdapter;
import org.eclipse.cdt.internal.core.pdom.indexer.IndexerASTVisitor;
import org.eclipse.cdt.internal.core.util.Canceler;
import org.eclipse.cdt.internal.core.util.ICanceler;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubMonitor;
import org.eclipse.osgi.util.NLS;
/**
* Abstract class to write information from AST.
* @since 4.0
*/
public abstract class PDOMWriter implements IPDOMASTProcessor {
private static final boolean REPORT_UNKNOWN_BUILTINS = false;
public static class FileInAST {
final IASTPreprocessorIncludeStatement includeStatement;
final FileContentKey fileContentKey;
final long timestamp;
final long fileSize;
final long contentsHash;
final long sourceReadTime;
final boolean hasError;
public FileInAST(IASTPreprocessorIncludeStatement includeStmt, FileContentKey key) {
includeStatement= includeStmt;
fileContentKey= key;
timestamp= includeStmt.getIncludedFileTimestamp();
fileSize = includeStmt.getIncludedFileSize();
contentsHash= includeStmt.getIncludedFileContentsHash();
sourceReadTime= includeStmt.getIncludedFileReadTime();
hasError= includeStmt.isErrorInIncludedFile();
}
public FileInAST(FileContentKey key, FileContent codeReader) {
includeStatement= null;
fileContentKey= key;
timestamp= codeReader.getTimestamp();
fileSize= codeReader.getFileSize();
contentsHash= codeReader.getContentsHash();
sourceReadTime= codeReader.getReadTime();
hasError= codeReader.hasError();
}
@Override
public String toString() {
return fileContentKey.toString();
}
}
public static class FileContext {
final IIndexFragmentFile fContext;
final IIndexFragmentFile fOldFile;
IIndexFragmentFile fNewFile;
public boolean fLostPragmaOnceSemantics;
public FileContext(IIndexFragmentFile context, IIndexFragmentFile oldFile) {
fContext= context;
fOldFile= oldFile;
fNewFile= null;
}
}
public static int SKIP_ALL_REFERENCES= -1;
public static int SKIP_TYPE_REFERENCES= 1;
public static int SKIP_MACRO_REFERENCES= 2;
public static int SKIP_IMPLICIT_REFERENCES= 4;
public static int SKIP_NO_REFERENCES= 0;
private static class Symbols {
final ArrayList<IASTName[]> fNames= new ArrayList<>();
final ArrayList<IASTPreprocessorStatement> fMacros= new ArrayList<>();
final ArrayList<IASTPreprocessorIncludeStatement> fIncludes= new ArrayList<>();
}
protected static class Data implements IIndexSymbols {
final IASTTranslationUnit fAST;
final FileInAST[] fSelectedFiles;
final IWritableIndex fIndex;
final Map<IASTPreprocessorIncludeStatement, Symbols> fSymbolMap = new HashMap<>();
final Set<IASTPreprocessorIncludeStatement> fContextIncludes = new HashSet<>();
final List<IStatus> fStatuses = new ArrayList<>();
Map<String, String> fReplacementHeaders; // Replacement headers keyed by file paths.
public Data(IASTTranslationUnit ast, FileInAST[] selectedFiles, IWritableIndex index) {
fAST= ast;
fSelectedFiles= selectedFiles;
fIndex= index;
for (FileInAST file : selectedFiles) {
fSymbolMap.put(file.includeStatement, new Symbols());
}
}
@Override
public boolean isEmpty() {
if (fSymbolMap.isEmpty())
return true;
for (Symbols symbols : fSymbolMap.values()) {
if (!symbols.fNames.isEmpty() || !symbols.fIncludes.isEmpty() || !symbols.fMacros.isEmpty()) {
return false;
}
}
return true;
}
@Override
public void add(IASTPreprocessorIncludeStatement owner, IASTName name, IASTName caller) {
Symbols lists= fSymbolMap.get(owner);
if (lists != null)
lists.fNames.add(new IASTName[] { name, caller });
}
@Override
public void add(IASTPreprocessorIncludeStatement owner, IASTPreprocessorIncludeStatement thing) {
Symbols lists= fSymbolMap.get(owner);
if (lists != null)
lists.fIncludes.add(thing);
}
@Override
public void add(IASTPreprocessorIncludeStatement owner, IASTPreprocessorStatement thing) {
Symbols lists= fSymbolMap.get(owner);
if (lists != null)
lists.fMacros.add(thing);
}
}
protected boolean fShowProblems;
protected boolean fShowInclusionProblems;
private boolean fShowScannerProblems;
private boolean fShowSyntaxProblems;
protected boolean fShowActivity;
protected final IndexerStatistics fStatistics;
protected final IndexerInputAdapter fResolver;
protected final ICanceler fCancelState = new Canceler();
private int fSkipReferences= SKIP_NO_REFERENCES;
public PDOMWriter(IndexerInputAdapter resolver) {
fStatistics= new IndexerStatistics();
fResolver= resolver;
}
protected IndexerInputAdapter getInputAdapter() {
return fResolver;
}
public void setShowActivity(boolean val) {
fShowActivity= val;
}
public void setShowInclusionProblems(boolean val) {
fShowInclusionProblems= val;
}
public void setShowScannerProblems(boolean val) {
fShowScannerProblems= val;
}
public void setShowSyntaxProblems(boolean val) {
fShowSyntaxProblems= val;
}
public void setShowProblems(boolean val) {
fShowProblems= val;
}
/**
* Determines whether references are skipped or not. Provide one of
* {@link #SKIP_ALL_REFERENCES}, {@link #SKIP_NO_REFERENCES} or a combination of
* {@link #SKIP_IMPLICIT_REFERENCES}, {@link #SKIP_TYPE_REFERENCES} and {@link #SKIP_MACRO_REFERENCES}.
*/
public void setSkipReferences(int options) {
fSkipReferences= options;
}
public int getSkipReferences() {
return fSkipReferences;
}
/**
* Extracts symbols from the given AST and adds them to the index. Ignores Data maps that are
* empty and ones where storageLinkageID == {@link ILinkage#NO_LINKAGE_ID}.
* <p>
* When flushIndex is set to <code>false</code>, you must make sure to flush
* the index after your last write operation.
*/
final protected void addSymbols(Data data, int storageLinkageID, FileContext ctx,
IProgressMonitor monitor) throws InterruptedException, CoreException {
if (data.isEmpty() || storageLinkageID == ILinkage.NO_LINKAGE_ID)
return;
if (fShowProblems) {
fShowInclusionProblems= true;
fShowScannerProblems= true;
fShowSyntaxProblems= true;
}
SubMonitor progress = SubMonitor.convert(monitor, 2);
// Name resolution.
resolveNames(data, progress.split(1));
// Index update.
storeSymbolsInIndex(data, storageLinkageID, ctx, progress.split(1));
if (!data.fStatuses.isEmpty()) {
List<IStatus> statuses = data.fStatuses;
String path= null;
if (data.fSelectedFiles.length > 0) {
path= data.fSelectedFiles[data.fSelectedFiles.length - 1].fileContentKey.getLocation().getURI().getPath();
} else {
path= data.fAST.getFilePath().toString();
}
String msg= NLS.bind(Messages.PDOMWriter_errorWhileParsing, path);
if (statuses.size() == 1) {
IStatus status= statuses.get(0);
if (msg.equals(status.getMessage())) {
throw new CoreException(status);
}
throw new CoreException(new Status(status.getSeverity(), status.getPlugin(), status.getCode(),
msg + ':' + status.getMessage(), status.getException()));
}
throw new CoreException(new MultiStatus(CCorePlugin.PLUGIN_ID, 0,
statuses.toArray(new IStatus[statuses.size()]), msg, null));
}
}
private void storeSymbolsInIndex(final Data data, int storageLinkageID, FileContext ctx,
IProgressMonitor monitor) throws InterruptedException, CoreException {
final IIndexFragmentFile newFile= ctx == null ? null : ctx.fNewFile;
SubMonitor progress = SubMonitor.convert(monitor, data.fSelectedFiles.length * 10);
for (int i= 0; i < data.fSelectedFiles.length; i++) {
final FileInAST fileInAST= data.fSelectedFiles[i];
if (fileInAST != null) {
if (fShowActivity) {
trace("Indexer: adding " + fileInAST.fileContentKey.getLocation().getURI()); //$NON-NLS-1$
}
Throwable th= null;
YieldableIndexLock lock = new YieldableIndexLock(data.fIndex, false, progress.split(1));
lock.acquire();
try {
final boolean isReplacement= ctx != null && fileInAST.includeStatement == null;
IIndexFragmentFile ifile= null;
if (!isReplacement || newFile == null) {
ifile= storeFileInIndex(data, fileInAST, storageLinkageID, lock, progress.split(9));
reportFileWrittenToIndex(fileInAST, ifile);
}
if (isReplacement) {
if (ifile == null)
ifile= newFile;
if (ctx != null && !ctx.fOldFile.equals(ifile) && ifile != null) {
if (ctx.fOldFile.hasPragmaOnceSemantics() && !ifile.hasPragmaOnceSemantics()) {
data.fIndex.transferContext(ctx.fOldFile, ifile);
ctx.fLostPragmaOnceSemantics= true;
} else {
data.fIndex.transferIncluders(ctx.fOldFile, ifile);
}
}
}
} catch (OperationCanceledException e) {
throw e;
} catch (RuntimeException | StackOverflowError | AssertionError e) {
th= e;
} finally {
// Because the caller holds a read-lock, the result cache of the index is never cleared.
// Before releasing the lock for the last time in this AST, we clear the result cache.
if (i == data.fSelectedFiles.length - 1) {
data.fIndex.clearResultCache();
}
lock.release();
}
if (th != null) {
data.fStatuses.add(createStatus(NLS.bind(Messages.PDOMWriter_errorWhileParsing,
fileInAST.fileContentKey.getLocation().getURI().getPath()), th));
}
fStatistics.fAddToIndexTime += lock.getCumulativeLockTime();
}
}
}
private void resolveNames(Data data, IProgressMonitor monitor) {
long start= System.currentTimeMillis();
SubMonitor progress = SubMonitor.convert(monitor, data.fSelectedFiles.length);
for (FileInAST file : data.fSelectedFiles) {
Symbols symbols= data.fSymbolMap.get(file.includeStatement);
final ArrayList<IASTName[]> names= symbols.fNames;
SubMonitor progress2 = SubMonitor.convert(progress, names.size());
boolean reported= false;
for (Iterator<IASTName[]> j = names.iterator(); j.hasNext();) {
final IASTName[] na= j.next();
final IASTName name = na[0];
progress2.split(1);
if (name != null) { // should not be null, just be defensive.
Throwable th= null;
try {
final IBinding binding = name.resolveBinding();
if (name.getPropertyInParent() == ICPPASTTemplateId.TEMPLATE_NAME &&
(((IASTName) name.getParent()).getBinding() == binding ||
binding instanceof ICPPFunctionTemplate)) {
na[0]= null;
} else if (binding instanceof IProblemBinding) {
IProblemBinding problemBinding = (IProblemBinding) binding;
if (REPORT_UNKNOWN_BUILTINS ||
problemBinding.getID() != IProblemBinding.BINDING_NOT_FOUND ||
!CharArrayUtils.startsWith(problemBinding.getNameCharArray(), "__builtin_")) { //$NON-NLS-1$
fStatistics.fProblemBindingCount++;
if (fShowProblems) {
reportProblem(problemBinding);
}
}
} else if (name.isReference()) {
if (binding instanceof ICPPTemplateParameter ||
binding instanceof ICPPUnknownBinding ||
((fSkipReferences & SKIP_TYPE_REFERENCES) != 0 &&
isTypeReferenceBinding(binding))) {
if (!isRequiredReference(name)) {
na[0]= null;
} else {
fStatistics.fReferenceCount++;
}
} else {
fStatistics.fReferenceCount++;
}
} else {
fStatistics.fDeclarationCount++;
}
} catch (RuntimeException e) {
th= e;
} catch (StackOverflowError e) {
th= e;
}
if (th != null) {
if (!reported) {
data.fStatuses.add(CCorePlugin.createStatus(NLS.bind(Messages.PDOMWriter_errorResolvingName,
name.toString(), file.fileContentKey.getLocation().getURI().getPath()), th));
}
reported= true;
j.remove();
}
}
}
}
fStatistics.fResolutionTime += System.currentTimeMillis() - start;
}
@Override
public int process(final IASTTranslationUnit ast, final IIndexSymbols symbols) throws CoreException {
if (!(symbols instanceof Data)) {
// TODO Fix this case -- the old implementation relies on the symbol map being exactly
// as expected.
CCorePlugin.log(IStatus.ERROR, "Default processor must receive expected Data type"); //$NON-NLS-1$
return ILinkage.NO_LINKAGE_ID;
}
int unresolvedIncludes= 0;
Data data = (Data) symbols;
final Map<IASTPreprocessorIncludeStatement, Symbols> symbolMap = data.fSymbolMap;
IASTPreprocessorStatement[] stmts = ast.getAllPreprocessorStatements();
for (final IASTPreprocessorStatement stmt : stmts) {
// Includes.
if (stmt instanceof IASTPreprocessorIncludeStatement) {
IASTPreprocessorIncludeStatement include= (IASTPreprocessorIncludeStatement) stmt;
final IASTFileLocation astLoc= include.getFileLocation();
IASTPreprocessorIncludeStatement owner = astLoc.getContextInclusionStatement();
final boolean updateSource= symbolMap.containsKey(owner);
if (updateSource) {
symbols.add(owner, include);
}
if (include.isActive()) {
if (!include.isResolved()) {
unresolvedIncludes++;
} else if (updateSource) {
// The include was parsed, check if we want to update the included file in the index.
if (symbolMap.containsKey(include)) {
data.fContextIncludes.add(include);
}
}
}
} else if (stmt.isActive() &&
(stmt instanceof IASTPreprocessorUndefStatement || stmt instanceof IASTPreprocessorMacroDefinition)) {
IASTFileLocation sourceLoc = stmt.getFileLocation();
if (sourceLoc != null) { // skip built-ins and command line macros
IASTPreprocessorIncludeStatement owner = sourceLoc.getContextInclusionStatement();
symbols.add(owner, stmt);
}
}
}
// Names.
final IndexerASTVisitor visitor = new IndexerASTVisitor((fSkipReferences & SKIP_IMPLICIT_REFERENCES) == 0) {
private int cancelationCheckThrottler;
@Override
public void visit(IASTName name, IASTName caller) {
checkForCancellation();
if (fSkipReferences == SKIP_ALL_REFERENCES) {
if (name.isReference()) {
if (!isRequiredReference(name)) {
return;
}
}
}
// Assign a location to anonymous types.
name= PDOMASTAdapter.getAdapterIfAnonymous(name);
if (name != null) {
IASTFileLocation nameLoc = name.getFileLocation();
if (nameLoc != null) {
IASTPreprocessorIncludeStatement owner= nameLoc.getContextInclusionStatement();
symbols.add(owner, name, caller);
}
}
}
private void checkForCancellation() {
if (cancelationCheckThrottler <= 0) {
if (fCancelState.isCanceled())
throw new OperationCanceledException();
cancelationCheckThrottler = 100;
} else {
cancelationCheckThrottler--;
}
}
};
ast.accept(visitor);
if ((fSkipReferences & SKIP_MACRO_REFERENCES) == 0) {
// Get a tree of definitions built by IndexerASTVisitor during its traversal.
// This is used to find enclosing definitions for macro references.
IndexerASTVisitor.Definition definitionTree = visitor.getDefinitionTree();
LocationMap lm= ast.getAdapter(LocationMap.class);
if (lm != null) {
IASTName[] refs= lm.getMacroReferences();
for (IASTName name : refs) {
IASTFileLocation nameLoc = name.getFileLocation();
if (nameLoc != null) {
IASTPreprocessorIncludeStatement owner= nameLoc.getContextInclusionStatement();
IASTName enclosingDefinition = definitionTree.search(nameLoc.getNodeOffset(),
nameLoc.getNodeLength());
symbols.add(owner, name, enclosingDefinition);
}
}
}
}
fStatistics.fUnresolvedIncludesCount += unresolvedIncludes;
fStatistics.fPreprocessorProblemCount += ast.getPreprocessorProblemsCount() - unresolvedIncludes;
if (fShowScannerProblems || fShowInclusionProblems) {
final boolean reportAll= fShowScannerProblems && fShowInclusionProblems;
IASTProblem[] scannerProblems= ast.getPreprocessorProblems();
for (IASTProblem problem : scannerProblems) {
if (reportAll || (problem.getID() == IProblem.PREPROCESSOR_INCLUSION_NOT_FOUND) == fShowInclusionProblems) {
reportProblem(problem);
}
}
}
final List<IASTProblem> problems= visitor.getProblems();
fStatistics.fSyntaxProblemsCount += problems.size();
if (fShowSyntaxProblems) {
for (IASTProblem problem : problems) {
reportProblem(problem);
}
}
return ast.getLinkage().getLinkageID();
}
protected final boolean isRequiredReference(IASTName name) {
IASTNode parentNode= name.getParent();
if (parentNode instanceof ICPPASTQualifiedName) {
if (name != ((ICPPASTQualifiedName) parentNode).getLastName())
return false;
parentNode= parentNode.getParent();
}
if (parentNode instanceof ICPPASTBaseSpecifier) {
return true;
} else if (parentNode instanceof IASTDeclSpecifier) {
IASTDeclSpecifier ds= (IASTDeclSpecifier) parentNode;
return ds.getStorageClass() == IASTDeclSpecifier.sc_typedef;
} else if (parentNode instanceof ICPPASTUsingDirective) {
return true;
}
return false;
}
private boolean isTypeReferenceBinding(IBinding binding) {
if (binding instanceof ICompositeType ||
binding instanceof IEnumeration ||
binding instanceof ITypedef ||
binding instanceof ICPPNamespace ||
binding instanceof ICPPNamespaceAlias ||
binding instanceof ICPPClassTemplate) {
return true;
}
return false;
}
private IIndexFragmentFile storeFileInIndex(Data data, FileInAST astFile, int storageLinkageID,
YieldableIndexLock lock, IProgressMonitor monitor) throws CoreException, InterruptedException {
final IWritableIndex index = data.fIndex;
IIndexFragmentFile file;
// We create a temporary PDOMFile with zero timestamp, add names to it, then replace
// contents of the old file from the temporary one, then delete the temporary file.
// The write lock on the index can be yielded between adding names to the temporary file,
// if another thread is waiting for a read lock.
final FileContentKey fileKey = astFile.fileContentKey;
final IASTPreprocessorIncludeStatement owner= astFile.includeStatement;
IIndexFileLocation location = fileKey.getLocation();
ISignificantMacros significantMacros = fileKey.getSignificantMacros();
IIndexFragmentFile oldFile = index.getWritableFile(storageLinkageID, location, significantMacros);
file= index.addUncommittedFile(storageLinkageID, location, significantMacros);
try {
boolean pragmaOnce= owner != null ? owner.hasPragmaOnceSemantics() : data.fAST.hasPragmaOnceSemantics();
file.setPragmaOnceSemantics(pragmaOnce);
if (data.fReplacementHeaders != null) {
String headerKey = IndexLocationFactory.getAbsolutePath(location).toOSString();
String replacementHeader = data.fReplacementHeaders.get(headerKey);
if (replacementHeader != null)
file.setReplacementHeader(replacementHeader);
}
Symbols lists= data.fSymbolMap.get(owner);
if (lists != null) {
IASTPreprocessorStatement[] macros= lists.fMacros.toArray(new IASTPreprocessorStatement[lists.fMacros.size()]);
IASTName[][] names= lists.fNames.toArray(new IASTName[lists.fNames.size()][]);
for (IASTName[] name2 : names) {
final IASTName name= name2[0];
if (name != null) {
ASTInternal.setFullyResolved(name.getBinding(), true);
}
}
List<IncludeInformation> includeInfos= new ArrayList<>();
for (int i= 0; i < lists.fIncludes.size(); i++) {
final IASTPreprocessorIncludeStatement stmt = lists.fIncludes.get(i);
if (!stmt.isResolved()) {
includeInfos.add(new IncludeInformation(stmt, null, ISignificantMacros.NONE, false));
} else {
IIndexFileLocation targetLoc = fResolver.resolveASTPath(stmt.getPath());
ISignificantMacros mainSig= stmt.getSignificantMacros();
for (ISignificantMacros sig : stmt.getLoadedVersions()) {
if (!sig.equals(mainSig)) {
includeInfos.add(new IncludeInformation(stmt, targetLoc, sig, false));
}
}
final boolean isContext = stmt.isActive() && stmt.isResolved() &&
(data.fContextIncludes.contains(stmt) || isContextFor(oldFile, stmt));
includeInfos.add(new IncludeInformation(stmt, targetLoc, mainSig, isContext));
}
}
IncludeInformation[] includeInfoArray= includeInfos.toArray(new IncludeInformation[includeInfos.size()]);
index.setFileContent(file, storageLinkageID, includeInfoArray, macros, names, fResolver, lock);
}
file.setTimestamp(astFile.hasError ? 0 : astFile.timestamp);
file.setSourceReadTime(astFile.sourceReadTime);
file.setSizeAndEncodingHashcode(computeFileSizeAndEncodingHashcode(astFile.fileSize, location));
file.setContentsHash(astFile.contentsHash);
file = index.commitUncommittedFile();
} finally {
index.clearUncommittedFile();
}
return file;
}
protected int computeFileSizeAndEncodingHashcode(IIndexFileLocation location) {
return computeFileSizeAndEncodingHashcode((int) fResolver.getFileSize(location), location);
}
private int computeFileSizeAndEncodingHashcode(long size, IIndexFileLocation location) {
return (int) size + 31 * fResolver.getEncoding(location).hashCode();
}
private boolean isContextFor(IIndexFragmentFile oldFile, IASTPreprocessorIncludeStatement stmt)
throws CoreException {
IIndexFile target= stmt.getImportedIndexFile();
if (oldFile != null && target != null) {
IIndexInclude ctxInclude = target.getParsedInContext();
if (ctxInclude != null && oldFile.equals(ctxInclude.getIncludedBy()))
return true;
}
return false;
}
/**
* Informs the subclass that a file has been stored in the index.
*/
protected abstract void reportFileWrittenToIndex(FileInAST file, IIndexFragmentFile iFile) throws CoreException;
private String getLocationInfo(String filename, int lineNumber) {
return " at " + filename + "(" + lineNumber + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
private void reportProblem(IProblemBinding problem) {
String msg= "Indexer: unresolved name" + getLocationInfo(problem.getFileName(), problem.getLineNumber()); //$NON-NLS-1$
String pmsg= problem.getMessage();
if (pmsg != null && pmsg.length() > 0)
msg += "; " + problem.getMessage(); //$NON-NLS-1$
trace(msg);
}
private void reportProblem(IASTProblem problem) {
String msg= "Indexer: " + problem.getMessageWithLocation(); //$NON-NLS-1$
trace(msg);
}
protected void reportException(Throwable th) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
th.printStackTrace(pw);
String msg= "Indexer: exception: " + sw.toString(); //$NON-NLS-1$
trace(msg);
}
protected void trace(String message) {
System.out.println(message);
}
protected IStatus createStatus(String msg) {
return CCorePlugin.createStatus(msg);
}
protected IStatus createStatus(String msg, Throwable e) {
return CCorePlugin.createStatus(msg, e);
}
public void cancel() {
fCancelState.setCanceled(true);
}
}