mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-04-29 19:45:01 +02:00
Implementation of an heuristics to resolve include files, bug 213562
This commit is contained in:
parent
ddd10d64c3
commit
a359eb6090
38 changed files with 1560 additions and 120 deletions
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2007 Wind River Systems, Inc. and others.
|
||||
* Copyright (c) 2006, 2008 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
|
||||
|
@ -23,7 +23,7 @@ import org.eclipse.jface.text.Region;
|
|||
|
||||
public class PositionTrackerTests extends TestCase {
|
||||
public static Test suite() {
|
||||
return new TestSuite(PositionTrackerTests.class, "PositionTrackerTests");
|
||||
return new TestSuite(PositionTrackerTests.class);
|
||||
}
|
||||
|
||||
public void testInitialFailures() {
|
||||
|
|
|
@ -0,0 +1,205 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.internal.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IFolder;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.NullProgressMonitor;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
|
||||
public class ResourceLookupTests extends TestCase {
|
||||
public static Test suite() {
|
||||
return new TestSuite(ResourceLookupTests.class);
|
||||
}
|
||||
|
||||
private IProject fProject;
|
||||
|
||||
@Override
|
||||
protected void setUp() {
|
||||
final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
|
||||
fProject= root.getProject("reslookup");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
fProject.delete(true, new NullProgressMonitor());
|
||||
}
|
||||
|
||||
protected IFolder createFolder(IProject project, String filename) throws CoreException {
|
||||
IFolder folder= project.getFolder(filename);
|
||||
folder.create(true, false, new NullProgressMonitor());
|
||||
return folder;
|
||||
}
|
||||
|
||||
protected IFile createFile(IProject project, String filename) throws CoreException {
|
||||
IFile file= project.getFile(filename);
|
||||
file.create(new InputStream() {
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
return -1;
|
||||
}}, true, new NullProgressMonitor());
|
||||
return file;
|
||||
}
|
||||
|
||||
public void testNameLookup() throws CoreException {
|
||||
IProject[] prjs= new IProject[]{fProject};
|
||||
|
||||
fProject.create(new NullProgressMonitor());
|
||||
fProject.open(new NullProgressMonitor());
|
||||
createFolder(fProject, "folder1");
|
||||
createFolder(fProject, "folder2");
|
||||
createFile(fProject, "abc.h");
|
||||
createFile(fProject, "folder1/abc.h");
|
||||
createFile(fProject, "folder2/abC.h");
|
||||
|
||||
IFile[] files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, false);
|
||||
assertEquals(2, files.length);
|
||||
files= ResourceLookup.findFilesByName(new Path("bla/../abc.h"), prjs, false);
|
||||
assertEquals(2, files.length);
|
||||
files= ResourceLookup.findFilesByName(new Path("../abc.h"), prjs, false);
|
||||
assertEquals(2, files.length);
|
||||
files= ResourceLookup.findFilesByName(new Path("../../abc.h"), prjs, false);
|
||||
assertEquals(2, files.length);
|
||||
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(3, files.length);
|
||||
|
||||
files= ResourceLookup.findFilesByName(new Path("folder1/abc.h"), prjs, false);
|
||||
assertEquals(1, files.length);
|
||||
files= ResourceLookup.findFilesByName(new Path("folder1/abC.h"), prjs, false);
|
||||
assertEquals(0, files.length);
|
||||
files= ResourceLookup.findFilesByName(new Path("fOlder1/abc.h"), prjs, false);
|
||||
assertEquals(0, files.length);
|
||||
|
||||
files= ResourceLookup.findFilesByName(new Path("folder1/abc.h"), prjs, true);
|
||||
assertEquals(1, files.length);
|
||||
files= ResourceLookup.findFilesByName(new Path("folder1/abC.h"), prjs, true);
|
||||
assertEquals(1, files.length);
|
||||
files= ResourceLookup.findFilesByName(new Path("fOlder1/abc.h"), prjs, true);
|
||||
assertEquals(1, files.length);
|
||||
|
||||
files= ResourceLookup.findFilesByName(new Path("bla/../abc.h"), prjs, true);
|
||||
assertEquals(3, files.length);
|
||||
}
|
||||
|
||||
public void testResourceDelta() throws CoreException {
|
||||
IProject[] prjs= new IProject[]{fProject};
|
||||
fProject.create(new NullProgressMonitor());
|
||||
fProject.open(new NullProgressMonitor());
|
||||
|
||||
IFile[] files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(0, files.length);
|
||||
|
||||
IFolder f1= createFolder(fProject, "folder1");
|
||||
createFolder(fProject, "folder2");
|
||||
IFile f2= createFile(fProject, "abc.h");
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(1, files.length);
|
||||
|
||||
createFile(fProject, "folder1/abc.h");
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(2, files.length);
|
||||
|
||||
createFile(fProject, "folder2/abC.h");
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(3, files.length);
|
||||
|
||||
f1.delete(true, new NullProgressMonitor());
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(2, files.length);
|
||||
|
||||
f2.delete(true, new NullProgressMonitor());
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(1, files.length);
|
||||
}
|
||||
|
||||
public void testDeref() throws CoreException {
|
||||
IProject[] prjs= new IProject[]{fProject};
|
||||
|
||||
fProject.create(new NullProgressMonitor());
|
||||
fProject.open(new NullProgressMonitor());
|
||||
createFolder(fProject, "folder1");
|
||||
createFolder(fProject, "folder2");
|
||||
createFile(fProject, "abc.h");
|
||||
IFile[] files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(1, files.length);
|
||||
|
||||
ResourceLookup.unrefNodeMap();
|
||||
createFile(fProject, "folder1/abc.h");
|
||||
createFile(fProject, "folder2/abC.h");
|
||||
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(3, files.length);
|
||||
|
||||
ResourceLookup.unrefNodeMap();
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(3, files.length);
|
||||
}
|
||||
|
||||
public void testCollected() throws CoreException {
|
||||
IProject[] prjs= new IProject[]{fProject};
|
||||
|
||||
fProject.create(new NullProgressMonitor());
|
||||
fProject.open(new NullProgressMonitor());
|
||||
createFolder(fProject, "folder1");
|
||||
createFolder(fProject, "folder2");
|
||||
createFile(fProject, "abc.h");
|
||||
IFile[] files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(1, files.length);
|
||||
|
||||
ResourceLookup.simulateNodeMapCollection();
|
||||
createFile(fProject, "folder1/abc.h");
|
||||
createFile(fProject, "folder2/abC.h");
|
||||
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(3, files.length);
|
||||
|
||||
ResourceLookup.simulateNodeMapCollection();
|
||||
files= ResourceLookup.findFilesByName(new Path("abc.h"), prjs, true);
|
||||
assertEquals(3, files.length);
|
||||
}
|
||||
|
||||
public void testFindFilesByLocation() throws Exception {
|
||||
IProject[] prjs= new IProject[]{fProject};
|
||||
|
||||
fProject.create(new NullProgressMonitor());
|
||||
fProject.open(new NullProgressMonitor());
|
||||
createFolder(fProject, "folder1");
|
||||
createFolder(fProject, "folder2");
|
||||
IFile file= createFile(fProject, "abc.h");
|
||||
createFile(fProject, "folder1/abc.h");
|
||||
createFile(fProject, "folder2/abC.h");
|
||||
|
||||
URI uri= file.getLocationURI();
|
||||
IFile[] files= ResourceLookup.findFilesForLocation(uri, prjs);
|
||||
assertEquals(1, files.length);
|
||||
|
||||
if (new File("a").equals(new File("A"))) {
|
||||
URI upperCase= new URI(uri.getScheme(), uri.getSchemeSpecificPart().toUpperCase(), uri.getFragment());
|
||||
files= ResourceLookup.findFilesForLocation(upperCase, prjs);
|
||||
assertEquals(1, files.length);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ import junit.framework.TestSuite;
|
|||
|
||||
public class StringBuilderTest extends TestCase {
|
||||
public static Test suite() {
|
||||
return new TestSuite(StringBuilderTest.class, "StringBuilderTest");
|
||||
return new TestSuite(StringBuilderTest.class);
|
||||
}
|
||||
|
||||
public void testSafe() {
|
||||
|
|
|
@ -334,8 +334,8 @@ public class LocationMapTests extends BaseTestCase {
|
|||
|
||||
public void testIncludes() {
|
||||
init(DIGITS);
|
||||
fLocationMap.encounterPoundInclude(0, 0, 0, 0, "n1".toCharArray(), null, true, false);
|
||||
fLocationMap.encounterPoundInclude(0, 1, 3, 16, "n2".toCharArray(), "f2", false , true);
|
||||
fLocationMap.encounterPoundInclude(0, 0, 0, 0, "n1".toCharArray(), null, true, false, false);
|
||||
fLocationMap.encounterPoundInclude(0, 1, 3, 16, "n2".toCharArray(), "f2", false , true, false);
|
||||
IASTPreprocessorIncludeStatement[] includes= fLocationMap.getIncludeDirectives();
|
||||
assertEquals(2, includes.length);
|
||||
checkInclude(includes[0], "", "", "n1", "", true, false, FN, 0, 0, 1, 0, 0);
|
||||
|
@ -495,11 +495,11 @@ public class LocationMapTests extends BaseTestCase {
|
|||
assertEquals(FN, fLocationMap.getCurrentFilePath());
|
||||
fLocationMap.encounteredComment(0,2,true);
|
||||
// number: [6,15)[25,26)
|
||||
ILocationCtx i1= fLocationMap.pushInclusion(0, 2, 4, 6, "b1b2b3b4b5".toCharArray(), "pre1", "pre1".toCharArray(), false);
|
||||
ILocationCtx i1= fLocationMap.pushInclusion(0, 2, 4, 6, "b1b2b3b4b5".toCharArray(), "pre1", "pre1".toCharArray(), false, false);
|
||||
assertEquals("pre1", fLocationMap.getCurrentFilePath());
|
||||
fLocationMap.encounteredComment(2,4,true);
|
||||
// number: [15,25)
|
||||
ILocationCtx i2= fLocationMap.pushInclusion(6, 7, 8, 9, "c1c2c3c4c5".toCharArray(), "pre11", "pre11".toCharArray(), false);
|
||||
ILocationCtx i2= fLocationMap.pushInclusion(6, 7, 8, 9, "c1c2c3c4c5".toCharArray(), "pre11", "pre11".toCharArray(), false, false);
|
||||
assertEquals("pre11", fLocationMap.getCurrentFilePath());
|
||||
fLocationMap.encounteredComment(2,6,true);
|
||||
fLocationMap.popContext(i2);
|
||||
|
@ -512,7 +512,7 @@ public class LocationMapTests extends BaseTestCase {
|
|||
fLocationMap.popContext(pre2);
|
||||
assertEquals(FN, fLocationMap.getCurrentFilePath());
|
||||
// number [36, 46)
|
||||
ILocationCtx i3= fLocationMap.pushInclusion(0, 2, 4, 6, "d1d2d3d4d5".toCharArray(), "pre2", "pre2".toCharArray(), false);
|
||||
ILocationCtx i3= fLocationMap.pushInclusion(0, 2, 4, 6, "d1d2d3d4d5".toCharArray(), "pre2", "pre2".toCharArray(), false, false);
|
||||
assertEquals("pre2", fLocationMap.getCurrentFilePath());
|
||||
fLocationMap.encounteredComment(0,2,true);
|
||||
fLocationMap.popContext(i3);
|
||||
|
|
|
@ -1350,4 +1350,53 @@ public class IndexBugsTests extends BaseTestCase {
|
|||
fIndex.releaseReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #include <header.h>
|
||||
// #define _CONCAT(x,y) x##y
|
||||
// #define CONCAT(x,y) _CONCAT(x,y)
|
||||
public void testIncludeHeuristics_Bug213562() throws Exception {
|
||||
String contents= getContentsForTest(1)[0];
|
||||
final IIndexManager indexManager = CCorePlugin.getIndexManager();
|
||||
TestSourceReader.createFile(fCProject.getProject(), "f1/g/header.h", "#define ID one\n");
|
||||
TestSourceReader.createFile(fCProject.getProject(), "f2/header.h", "#define ID two\n");
|
||||
TestSourceReader.createFile(fCProject.getProject(), "f1/g/h/header.h", "#define ID three\n");
|
||||
TestSourceReader.createFile(fCProject.getProject(), "f1/g/source.cpp", contents + "int CONCAT(one, ID);\n");
|
||||
TestSourceReader.createFile(fCProject.getProject(), "f2/g/source.cpp", contents + "int CONCAT(two, ID);\n");
|
||||
TestSourceReader.createFile(fCProject.getProject(), "f1/g/h/source.cpp", contents + "int CONCAT(three, ID);\n");
|
||||
indexManager.reindex(fCProject);
|
||||
waitForIndexer();
|
||||
fIndex.acquireReadLock();
|
||||
try {
|
||||
IIndexBinding[] bindings= fIndex.findBindings("oneone".toCharArray(), IndexFilter.ALL_DECLARED, new NullProgressMonitor());
|
||||
assertEquals(1, bindings.length);
|
||||
bindings= fIndex.findBindings("twotwo".toCharArray(), IndexFilter.ALL_DECLARED, new NullProgressMonitor());
|
||||
assertEquals(1, bindings.length);
|
||||
bindings= fIndex.findBindings("threethree".toCharArray(), IndexFilter.ALL_DECLARED, new NullProgressMonitor());
|
||||
assertEquals(1, bindings.length);
|
||||
} finally {
|
||||
fIndex.releaseReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public void testIncludeHeuristicsFlag_Bug213562() throws Exception {
|
||||
final IIndexManager indexManager = CCorePlugin.getIndexManager();
|
||||
TestSourceReader.createFile(fCProject.getProject(), "f1/header.h", "");
|
||||
IFile f1= TestSourceReader.createFile(fCProject.getProject(), "source1.cpp", "#include \"header.h\"\n");
|
||||
IFile f2= TestSourceReader.createFile(fCProject.getProject(), "source2.cpp", "#include \"f1/header.h\"\n");
|
||||
indexManager.reindex(fCProject);
|
||||
waitForIndexer();
|
||||
fIndex.acquireReadLock();
|
||||
try {
|
||||
IIndexFile f= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f1));
|
||||
IIndexInclude i= f.getIncludes()[0];
|
||||
assertTrue(i.isResolvedByHeuristics());
|
||||
|
||||
f= fIndex.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL(f2));
|
||||
i= f.getIncludes()[0];
|
||||
assertFalse(i.isResolvedByHeuristics());
|
||||
} finally {
|
||||
fIndex.releaseReadLock();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ import junit.framework.TestSuite;
|
|||
import org.eclipse.cdt.core.cdescriptor.tests.CDescriptorTests;
|
||||
import org.eclipse.cdt.core.internal.errorparsers.tests.ErrorParserTests;
|
||||
import org.eclipse.cdt.core.internal.tests.PositionTrackerTests;
|
||||
import org.eclipse.cdt.core.internal.tests.ResourceLookupTests;
|
||||
import org.eclipse.cdt.core.internal.tests.StringBuilderTest;
|
||||
import org.eclipse.cdt.core.language.AllLanguageTests;
|
||||
import org.eclipse.cdt.core.model.tests.AllCoreTests;
|
||||
|
@ -61,6 +62,7 @@ public class AutomatedIntegrationSuite extends TestSuite {
|
|||
suite.addTest(ElementDeltaTests.suite());
|
||||
suite.addTest(WorkingCopyTests.suite());
|
||||
suite.addTest(PositionTrackerTests.suite());
|
||||
suite.addTest(ResourceLookupTests.suite());
|
||||
suite.addTest(StringBuilderTest.suite());
|
||||
suite.addTest(AllLanguageTests.suite());
|
||||
suite.addTest(RewriteTests.suite());
|
||||
|
|
|
@ -71,6 +71,7 @@ Export-Package: org.eclipse.cdt.core,
|
|||
org.eclipse.cdt.internal.core.pdom.dom.cpp;x-internal:=true,
|
||||
org.eclipse.cdt.internal.core.pdom.export;x-internal:=true,
|
||||
org.eclipse.cdt.internal.core.pdom.indexer;x-friends:="org.eclipse.cdt.ui",
|
||||
org.eclipse.cdt.internal.core.resources;x-internal:=true,
|
||||
org.eclipse.cdt.internal.core.util;x-internal:=true,
|
||||
org.eclipse.cdt.internal.errorparsers;x-internal:=true,
|
||||
org.eclipse.cdt.internal.formatter;x-internal:=true,
|
||||
|
|
|
@ -70,6 +70,7 @@ import org.eclipse.cdt.internal.core.dom.NullCodeReaderFactory;
|
|||
import org.eclipse.cdt.internal.core.dom.SavedCodeReaderFactory;
|
||||
import org.eclipse.cdt.internal.core.index.IndexBasedCodeReaderFactory;
|
||||
import org.eclipse.cdt.internal.core.parser.ParserLogService;
|
||||
import org.eclipse.cdt.internal.core.pdom.indexer.ProjectIndexerIncludeResolutionHeuristics;
|
||||
import org.eclipse.cdt.internal.core.pdom.indexer.ProjectIndexerInputAdapter;
|
||||
import org.eclipse.cdt.internal.core.util.ICanceler;
|
||||
import org.eclipse.cdt.internal.core.util.MementoTokenizer;
|
||||
|
@ -835,15 +836,20 @@ public class TranslationUnit extends Openable implements ITranslationUnit {
|
|||
}
|
||||
|
||||
private ICodeReaderFactory getCodeReaderFactory(int style, IIndex index, int linkageID) {
|
||||
final ICProject cprj= getCProject();
|
||||
final ProjectIndexerInputAdapter pathResolver = new ProjectIndexerInputAdapter(cprj);
|
||||
final ProjectIndexerIncludeResolutionHeuristics heuristics = new ProjectIndexerIncludeResolutionHeuristics(cprj.getProject(), pathResolver);
|
||||
ICodeReaderFactory codeReaderFactory;
|
||||
if ((style & AST_SKIP_NONINDEXED_HEADERS) != 0) {
|
||||
codeReaderFactory= NullCodeReaderFactory.getInstance();
|
||||
} else {
|
||||
codeReaderFactory= SavedCodeReaderFactory.getInstance();
|
||||
codeReaderFactory= SavedCodeReaderFactory.createInstance(heuristics);
|
||||
}
|
||||
|
||||
if (index != null && (style & AST_SKIP_INDEXED_HEADERS) != 0) {
|
||||
IndexBasedCodeReaderFactory ibcf= new IndexBasedCodeReaderFactory(index, new ProjectIndexerInputAdapter(getCProject()), linkageID, codeReaderFactory);
|
||||
IndexBasedCodeReaderFactory ibcf= new IndexBasedCodeReaderFactory(index,
|
||||
heuristics,
|
||||
pathResolver, linkageID, codeReaderFactory);
|
||||
if ((style & AST_CONFIGURE_USING_SOURCE_CONTEXT) != 0) {
|
||||
ibcf.setSupportFillGapFromContextToHeader(true);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2007 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 2008 IBM Corporation 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:
|
||||
* IBM - Initial API and implementation
|
||||
* Markus Schorn (Wind River Systems)
|
||||
* IBM - Initial API and implementation
|
||||
* Markus Schorn (Wind River Systems)
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.dom.ast;
|
||||
|
||||
/**
|
||||
* This interface represent a preprocessor #include statement.
|
||||
*
|
||||
* @author jcamelon
|
||||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
public interface IASTPreprocessorIncludeStatement extends
|
||||
IASTPreprocessorStatement {
|
||||
|
@ -57,4 +57,10 @@ public interface IASTPreprocessorIncludeStatement extends
|
|||
* @since 4.0
|
||||
*/
|
||||
public boolean isResolved();
|
||||
|
||||
/**
|
||||
* Returns whether the inclusion was resolved using a heuristics.
|
||||
* @since 5.1
|
||||
*/
|
||||
public boolean isResolvedByHeuristics();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2007 Wind River Systems, Inc. and others.
|
||||
* Copyright (c) 2006, 2008 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
|
||||
|
@ -9,23 +9,14 @@
|
|||
* Markus Schorn - initial API and implementation
|
||||
* Andrew Ferguson (Symbian)
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.cdt.core.index;
|
||||
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
|
||||
/**
|
||||
* Interface for an include directive stored in the index.
|
||||
* <p>
|
||||
* This interface is not intended to be implemented by clients.
|
||||
* </p>
|
||||
* <p>
|
||||
* <strong>EXPERIMENTAL</strong>. This class or interface has been added as
|
||||
* part of a work in progress. There is no guarantee that this API will work or
|
||||
* that it will remain the same. Please do not use this API without consulting
|
||||
* with the CDT team.
|
||||
* </p>
|
||||
*
|
||||
* @noimplement This interface is not intended to be implemented by clients.
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface IIndexInclude {
|
||||
|
@ -106,4 +97,11 @@ public interface IIndexInclude {
|
|||
* @throws CoreException
|
||||
*/
|
||||
boolean isResolved() throws CoreException;
|
||||
|
||||
/**
|
||||
* Tests whether this include has been resolved using a heuristics rather than relying on
|
||||
* the include search path.
|
||||
* @since 5.1
|
||||
*/
|
||||
boolean isResolvedByHeuristics() throws CoreException;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,8 @@ import org.eclipse.cdt.core.index.IIndexMacro;
|
|||
import org.eclipse.cdt.core.parser.CodeReader;
|
||||
import org.eclipse.cdt.core.parser.ICodeReaderCache;
|
||||
import org.eclipse.cdt.core.parser.ParserUtil;
|
||||
import org.eclipse.cdt.internal.core.dom.AbstractCodeReaderFactory;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.IIndexBasedCodeReaderFactory;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.IncludeFileContent;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.IncludeFileContent.InclusionKind;
|
||||
|
@ -46,7 +48,7 @@ import org.eclipse.core.runtime.CoreException;
|
|||
* Code reader factory, that fakes code readers for header files already stored in the
|
||||
* index.
|
||||
*/
|
||||
public final class IndexBasedCodeReaderFactory implements IIndexBasedCodeReaderFactory {
|
||||
public final class IndexBasedCodeReaderFactory extends AbstractCodeReaderFactory implements IIndexBasedCodeReaderFactory {
|
||||
private static final class NeedToParseException extends Exception {}
|
||||
private static final String GAP = "__gap__"; //$NON-NLS-1$
|
||||
|
||||
|
@ -59,13 +61,15 @@ public final class IndexBasedCodeReaderFactory implements IIndexBasedCodeReaderF
|
|||
private final AbstractIndexerTask fRelatedIndexerTask;
|
||||
private boolean fSupportFillGapFromContextToHeader= false;
|
||||
|
||||
public IndexBasedCodeReaderFactory(IIndex index, ASTFilePathResolver pathResolver, int linkage,
|
||||
ICodeReaderFactory fallbackFactory) {
|
||||
this(index, pathResolver, linkage, fallbackFactory, null);
|
||||
public IndexBasedCodeReaderFactory(IIndex index, IIncludeFileResolutionHeuristics heuristics,
|
||||
ASTFilePathResolver pathResolver, int linkage, ICodeReaderFactory fallbackFactory) {
|
||||
this(index, heuristics, pathResolver, linkage, fallbackFactory, null);
|
||||
}
|
||||
|
||||
public IndexBasedCodeReaderFactory(IIndex index, ASTFilePathResolver pathResolver, int linkage,
|
||||
public IndexBasedCodeReaderFactory(IIndex index, IIncludeFileResolutionHeuristics heuristics,
|
||||
ASTFilePathResolver pathResolver, int linkage,
|
||||
ICodeReaderFactory fallbackFactory, AbstractIndexerTask relatedIndexerTask) {
|
||||
super(heuristics);
|
||||
fIndex= index;
|
||||
fFallBackFactory= fallbackFactory;
|
||||
fPathResolver= pathResolver;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2007 QNX Software Systems and others.
|
||||
* Copyright (c) 2006, 2008 QNX Software Systems 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
|
||||
|
@ -16,6 +16,7 @@ package org.eclipse.cdt.internal.core.indexer;
|
|||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
|
||||
/**
|
||||
* A task for index updates.
|
||||
|
@ -38,4 +39,9 @@ public class StandaloneFastIndexerTask extends StandaloneIndexerTask {
|
|||
protected ICodeReaderFactory createReaderFactory() {
|
||||
return new StandaloneIndexerFallbackReaderFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIncludeFileResolutionHeuristics createIncludeHeuristics() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2007 QNX Software Systems and others.
|
||||
* Copyright (c) 2006, 2008 QNX Software Systems 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
|
||||
|
@ -16,6 +16,7 @@ package org.eclipse.cdt.internal.core.indexer;
|
|||
import java.util.List;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
|
||||
/**
|
||||
* A task for index updates.
|
||||
|
@ -39,4 +40,9 @@ public class StandaloneFullIndexerTask extends StandaloneIndexerTask {
|
|||
protected ICodeReaderFactory createReaderFactory() {
|
||||
return ((StandaloneFullIndexer)fIndexer).getCodeReaderFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIncludeFileResolutionHeuristics createIncludeHeuristics() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -212,16 +212,18 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces
|
|||
private final boolean fIsActive;
|
||||
private final boolean fIsResolved;
|
||||
private final boolean fIsSystemInclude;
|
||||
private final boolean fFoundByHeuristics;
|
||||
|
||||
public ASTInclusionStatement(IASTTranslationUnit parent,
|
||||
int startNumber, int nameStartNumber, int nameEndNumber, int endNumber,
|
||||
char[] headerName, String filePath, boolean userInclude, boolean active) {
|
||||
char[] headerName, String filePath, boolean userInclude, boolean active, boolean heuristic) {
|
||||
super(parent, IASTTranslationUnit.PREPROCESSOR_STATEMENT, startNumber, endNumber);
|
||||
fName= new ASTPreprocessorName(this, IASTPreprocessorIncludeStatement.INCLUDE_NAME, nameStartNumber, nameEndNumber, headerName, null);
|
||||
fPath= filePath == null ? "" : filePath; //$NON-NLS-1$
|
||||
fIsActive= active;
|
||||
fIsResolved= filePath != null;
|
||||
fIsSystemInclude= !userInclude;
|
||||
fFoundByHeuristics= heuristic;
|
||||
}
|
||||
|
||||
public IASTName getName() {
|
||||
|
@ -249,6 +251,10 @@ class ASTInclusionStatement extends ASTPreprocessorNode implements IASTPreproces
|
|||
super.findNode(nodeSpec);
|
||||
nodeSpec.visit(fName);
|
||||
}
|
||||
|
||||
public boolean isResolvedByHeuristics() {
|
||||
return fFoundByHeuristics;
|
||||
}
|
||||
}
|
||||
|
||||
class ASTMacroDefinition extends ASTPreprocessorNode implements IASTPreprocessorObjectStyleMacroDefinition {
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.eclipse.cdt.core.parser.ParserLanguage;
|
|||
import org.eclipse.cdt.core.parser.util.CharArrayIntMap;
|
||||
import org.eclipse.cdt.core.parser.util.CharArrayMap;
|
||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.ExpressionEvaluator.EvalException;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.IncludeFileContent.InclusionKind;
|
||||
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
|
||||
|
@ -87,21 +88,29 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
private static final DynamicMacro __LINE__ = new LineMacro("__LINE__".toCharArray()); //$NON-NLS-1$
|
||||
|
||||
private interface IIncludeFileTester<T> {
|
||||
T checkFile(String path, String fileName);
|
||||
T checkFile(String path, String fileName, boolean isHeuristicMatch);
|
||||
}
|
||||
|
||||
final private IIncludeFileTester<IncludeFileContent> createCodeReaderTester= new IIncludeFileTester<IncludeFileContent>() {
|
||||
public IncludeFileContent checkFile(String path, String fileName) {
|
||||
String finalPath = ScannerUtility.createReconciledPath(path, fileName);
|
||||
return fCodeReaderFactory.getContentForInclusion(finalPath);
|
||||
public IncludeFileContent checkFile(String path, String fileName, boolean isHeuristicMatch) {
|
||||
final String finalPath = ScannerUtility.createReconciledPath(path, fileName);
|
||||
final IncludeFileContent fc= fCodeReaderFactory.getContentForInclusion(finalPath);
|
||||
if (fc != null) {
|
||||
fc.setFoundByHeuristics(isHeuristicMatch);
|
||||
}
|
||||
return fc;
|
||||
}
|
||||
};
|
||||
|
||||
final private IIncludeFileTester<String> createPathTester= new IIncludeFileTester<String>() {
|
||||
public String checkFile(String path, String fileName) {
|
||||
private static class IncludeResolution {String fLocation; boolean fHeuristic;}
|
||||
final private IIncludeFileTester<IncludeResolution> createPathTester= new IIncludeFileTester<IncludeResolution>() {
|
||||
public IncludeResolution checkFile(String path, String fileName, boolean isHeuristicMatch) {
|
||||
String finalPath= ScannerUtility.createReconciledPath(path, fileName);
|
||||
if (fCodeReaderFactory.getInclusionExists(finalPath)) {
|
||||
return finalPath;
|
||||
IncludeResolution res= new IncludeResolution();
|
||||
res.fHeuristic= isHeuristicMatch;
|
||||
res.fLocation= finalPath;
|
||||
return res;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -109,6 +118,8 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
|
||||
final private IParserLogService fLog;
|
||||
final private IIndexBasedCodeReaderFactory fCodeReaderFactory;
|
||||
|
||||
private IIncludeFileResolutionHeuristics fIncludeFileResolutionHeuristics;
|
||||
private final ExpressionEvaluator fExpressionEvaluator;
|
||||
private final MacroDefinitionParser fMacroDefinitionParser;
|
||||
private final MacroExpander fMacroExpander;
|
||||
|
@ -142,7 +153,6 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
private Token fPrefetchedTokens;
|
||||
private Token fLastToken;
|
||||
|
||||
|
||||
public CPreprocessor(CodeReader reader, IScannerInfo info, ParserLanguage language, IParserLogService log,
|
||||
IScannerExtensionConfiguration configuration, ICodeReaderFactory readerFactory) {
|
||||
fLog = log;
|
||||
|
@ -162,6 +172,9 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
fMacroDefinitionParser= new MacroDefinitionParser();
|
||||
fMacroExpander= new MacroExpander(this, fMacroDictionary, fLocationMap, fLexOptions);
|
||||
fCodeReaderFactory= wrapReaderFactory(readerFactory);
|
||||
if (readerFactory instanceof IAdaptable) {
|
||||
fIncludeFileResolutionHeuristics= (IIncludeFileResolutionHeuristics) ((IAdaptable) readerFactory).getAdapter(IIncludeFileResolutionHeuristics.class);
|
||||
}
|
||||
|
||||
setupMacroDictionary(configuration, info, language);
|
||||
|
||||
|
@ -746,43 +759,50 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
}
|
||||
}
|
||||
|
||||
private IncludeFileContent findInclusion(final String filename, final boolean quoteInclude,
|
||||
final boolean includeNext, final File currentDir) {
|
||||
return findInclusion(filename, quoteInclude, includeNext, currentDir, createCodeReaderTester);
|
||||
}
|
||||
|
||||
private <T> T findInclusion(final String filename, final boolean quoteInclude,
|
||||
final boolean includeNext, final File currentDirectory, final IIncludeFileTester<T> tester) {
|
||||
final boolean includeNext, final String currentFile, final IIncludeFileTester<T> tester) {
|
||||
T reader = null;
|
||||
// filename is an absolute path or it is a Linux absolute path on a windows machine
|
||||
if (new File(filename).isAbsolute() || filename.startsWith("/")) { //$NON-NLS-1$
|
||||
return tester.checkFile( EMPTY_STRING, filename );
|
||||
return tester.checkFile(EMPTY_STRING, filename, false);
|
||||
}
|
||||
|
||||
if (currentDirectory != null && quoteInclude && !includeNext) {
|
||||
|
||||
if (currentFile != null && quoteInclude && !includeNext) {
|
||||
// Check to see if we find a match in the current directory
|
||||
String absolutePath = currentDirectory.getAbsolutePath();
|
||||
reader = tester.checkFile(absolutePath, filename);
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
final File currentDir= new File(currentFile).getParentFile();
|
||||
if (currentDir != null) {
|
||||
String absolutePath = currentDir.getAbsolutePath();
|
||||
reader = tester.checkFile(absolutePath, filename, false);
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we're not include_next, then we are looking for the first occurrence of
|
||||
// the file, otherwise, we ignore all the paths before the current directory
|
||||
final String[] isp= quoteInclude ? fQuoteIncludePaths : fIncludePaths;
|
||||
if (isp != null ) {
|
||||
if (isp != null) {
|
||||
int i=0;
|
||||
if (includeNext && currentDirectory != null) {
|
||||
i= findIncludePos(isp, currentDirectory) + 1;
|
||||
if (includeNext && currentFile != null) {
|
||||
final File currentDir= new File(currentFile).getParentFile();
|
||||
if (currentDir != null) {
|
||||
i= findIncludePos(isp, currentDir) + 1;
|
||||
}
|
||||
}
|
||||
for (; i < isp.length; ++i) {
|
||||
reader= tester.checkFile(isp[i], filename);
|
||||
reader= tester.checkFile(isp[i], filename, false);
|
||||
if (reader != null) {
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fIncludeFileResolutionHeuristics != null) {
|
||||
String location= fIncludeFileResolutionHeuristics.findInclusion(filename, currentFile);
|
||||
if (location != null) {
|
||||
return tester.checkFile(null, location, true);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1027,20 +1047,21 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
|
||||
String path= null;
|
||||
boolean reported= false;
|
||||
boolean isHeuristic= false;
|
||||
|
||||
if (!active) {
|
||||
// test if the include is inactive just because it was included before (bug 167100)
|
||||
final File currentDir= userInclude || include_next ? new File(String.valueOf(getCurrentFilename())).getParentFile() : null;
|
||||
final String resolved= findInclusion(new String(headerName), userInclude, include_next, currentDir, createPathTester);
|
||||
if (resolved != null && fCodeReaderFactory.hasFileBeenIncludedInCurrentTranslationUnit(resolved)) {
|
||||
path= resolved;
|
||||
final IncludeResolution resolved= findInclusion(new String(headerName), userInclude, include_next, getCurrentFilename(), createPathTester);
|
||||
if (resolved != null && fCodeReaderFactory.hasFileBeenIncludedInCurrentTranslationUnit(resolved.fLocation)) {
|
||||
path= resolved.fLocation;
|
||||
isHeuristic= resolved.fHeuristic;
|
||||
}
|
||||
}
|
||||
else {
|
||||
final File currentDir= userInclude || include_next ? new File(String.valueOf(getCurrentFilename())).getParentFile() : null;
|
||||
final IncludeFileContent fi= findInclusion(new String(headerName), userInclude, include_next, currentDir);
|
||||
final IncludeFileContent fi= findInclusion(new String(headerName), userInclude, include_next, getCurrentFilename(), createCodeReaderTester);
|
||||
if (fi != null) {
|
||||
path= fi.getFileLocation();
|
||||
isHeuristic= fi.isFoundByHeuristics();
|
||||
switch(fi.getKind()) {
|
||||
case FOUND_IN_INDEX:
|
||||
processInclusionFromIndex(poundOffset, path, fi);
|
||||
|
@ -1050,7 +1071,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
if (reader != null && !isCircularInclusion(path)) {
|
||||
reported= true;
|
||||
fAllIncludedFiles.add(path);
|
||||
ILocationCtx ctx= fLocationMap.pushInclusion(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, reader.buffer, path, headerName, userInclude);
|
||||
ILocationCtx ctx= fLocationMap.pushInclusion(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, reader.buffer, path, headerName, userInclude, isHeuristic);
|
||||
ScannerContext fctx= new ScannerContext(ctx, fCurrentContext, new Lexer(reader.buffer, fLexOptions, this, this));
|
||||
fCurrentContext= fctx;
|
||||
}
|
||||
|
@ -1074,7 +1095,7 @@ public class CPreprocessor implements ILexerLog, IScanner, IAdaptable {
|
|||
}
|
||||
|
||||
if (!reported) {
|
||||
fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, headerName, path, userInclude, active);
|
||||
fLocationMap.encounterPoundInclude(poundOffset, nameOffsets[0], nameOffsets[1], condEndOffset, headerName, path, userInclude, active, isHeuristic);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ public class IncludeFileContent {
|
|||
private final List<IIndexMacro> fMacroDefinitions;
|
||||
private final List<ICPPUsingDirective> fUsingDirectives;
|
||||
private final String fFileLocation;
|
||||
private boolean fHeuristic;
|
||||
private List<IIndexFile> fFiles;
|
||||
|
||||
/**
|
||||
|
@ -144,4 +145,15 @@ public class IncludeFileContent {
|
|||
public List<IIndexFile> getFilesIncluded() {
|
||||
return fFiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this inclusion was found by a heuristics.
|
||||
*/
|
||||
public boolean isFoundByHeuristics() {
|
||||
return fHeuristic;
|
||||
}
|
||||
|
||||
public void setFoundByHeuristics(boolean val) {
|
||||
fHeuristic= val;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,14 +116,14 @@ public class LocationMap implements ILocationResolver {
|
|||
* @param userInclude <code>true</code> when specified with double-quotes.
|
||||
*/
|
||||
public ILocationCtx pushInclusion(int startOffset, int nameOffset, int nameEndOffset, int endOffset,
|
||||
char[] buffer, String filename, char[] name, boolean userInclude) {
|
||||
char[] buffer, String filename, char[] name, boolean userInclude, boolean heuristic) {
|
||||
assert fCurrentContext instanceof LocationCtxContainer;
|
||||
int startNumber= getSequenceNumberForOffset(startOffset);
|
||||
int nameNumber= getSequenceNumberForOffset(nameOffset);
|
||||
int nameEndNumber= getSequenceNumberForOffset(nameEndOffset);
|
||||
int endNumber= getSequenceNumberForOffset(endOffset);
|
||||
final ASTInclusionStatement inclusionStatement=
|
||||
new ASTInclusionStatement(fTranslationUnit, startNumber, nameNumber, nameEndNumber, endNumber, name, filename, userInclude, true);
|
||||
new ASTInclusionStatement(fTranslationUnit, startNumber, nameNumber, nameEndNumber, endNumber, name, filename, userInclude, true, heuristic);
|
||||
fDirectives.add(inclusionStatement);
|
||||
fCurrentContext= new LocationCtxFile((LocationCtxContainer) fCurrentContext, filename, buffer, startOffset, endOffset, endNumber, inclusionStatement);
|
||||
fLastChildInsertionOffset= 0;
|
||||
|
@ -218,12 +218,12 @@ public class LocationMap implements ILocationResolver {
|
|||
* @param active <code>true</code> when include appears in active code.
|
||||
*/
|
||||
public void encounterPoundInclude(int startOffset, int nameOffset, int nameEndOffset, int endOffset,
|
||||
char[] name, String filename, boolean userInclude, boolean active) {
|
||||
char[] name, String filename, boolean userInclude, boolean active, boolean heuristic) {
|
||||
startOffset= getSequenceNumberForOffset(startOffset);
|
||||
nameOffset= getSequenceNumberForOffset(nameOffset);
|
||||
nameEndOffset= getSequenceNumberForOffset(nameEndOffset);
|
||||
endOffset= getSequenceNumberForOffset(endOffset);
|
||||
fDirectives.add(new ASTInclusionStatement(fTranslationUnit, startOffset, nameOffset, nameEndOffset, endOffset, name, filename, userInclude, active));
|
||||
fDirectives.add(new ASTInclusionStatement(fTranslationUnit, startOffset, nameOffset, nameEndOffset, endOffset, name, filename, userInclude, active, heuristic));
|
||||
}
|
||||
|
||||
public void encounteredComment(int offset, int endOffset, boolean isBlockComment) {
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.eclipse.cdt.core.parser.IParserLogService;
|
|||
import org.eclipse.cdt.core.parser.IScannerInfo;
|
||||
import org.eclipse.cdt.core.parser.ParserUtil;
|
||||
import org.eclipse.cdt.core.parser.ScannerInfo;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
import org.eclipse.cdt.internal.core.index.IIndexFragmentFile;
|
||||
import org.eclipse.cdt.internal.core.index.IWritableIndex;
|
||||
import org.eclipse.cdt.internal.core.index.IndexBasedCodeReaderFactory;
|
||||
|
@ -134,6 +135,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
|||
}
|
||||
|
||||
protected abstract IWritableIndex createIndex();
|
||||
protected abstract IIncludeFileResolutionHeuristics createIncludeHeuristics();
|
||||
protected abstract ICodeReaderFactory createReaderFactory();
|
||||
protected abstract AbstractLanguage[] getLanguages(String fileName);
|
||||
|
||||
|
@ -178,7 +180,7 @@ public abstract class AbstractIndexerTask extends PDOMWriter {
|
|||
IScannerInfo scanInfo, int options, IProgressMonitor pm) throws CoreException {
|
||||
if (fCodeReaderFactory == null) {
|
||||
if (fIsFastIndexer) {
|
||||
fCodeReaderFactory= new IndexBasedCodeReaderFactory(fIndex, fResolver, language.getLinkageID(), createReaderFactory(), this);
|
||||
fCodeReaderFactory= new IndexBasedCodeReaderFactory(fIndex, createIncludeHeuristics(), fResolver, language.getLinkageID(), createReaderFactory(), this);
|
||||
}
|
||||
else {
|
||||
fCodeReaderFactory= createReaderFactory();
|
||||
|
|
|
@ -89,6 +89,10 @@ abstract public class PDOMWriter {
|
|||
fResolver= resolver;
|
||||
}
|
||||
|
||||
protected IndexerInputAdapter getInputAdapter() {
|
||||
return fResolver;
|
||||
}
|
||||
|
||||
public void setShowActivity(boolean val) {
|
||||
fShowActivity= val;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ public class PDOMInclude implements IIndexFragmentInclude {
|
|||
private static final int FLAG_SYSTEM_INCLUDE = 1;
|
||||
private static final int FLAG_INACTIVE_INCLUDE = 2;
|
||||
private static final int FLAG_UNRESOLVED_INCLUDE = 4;
|
||||
private static final int FLAG_RESOLVED_BY_HEURISTICS= 8;
|
||||
|
||||
private final PDOM pdom;
|
||||
private final int record;
|
||||
|
@ -81,6 +82,8 @@ public class PDOMInclude implements IIndexFragmentInclude {
|
|||
}
|
||||
if (unresolved) {
|
||||
flags |= FLAG_UNRESOLVED_INCLUDE;
|
||||
} else if (include.isResolvedByHeuristics()) {
|
||||
flags |= FLAG_RESOLVED_BY_HEURISTICS;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
@ -224,7 +227,11 @@ public class PDOMInclude implements IIndexFragmentInclude {
|
|||
public boolean isResolved() throws CoreException {
|
||||
return (getFlag() & FLAG_UNRESOLVED_INCLUDE) == 0;
|
||||
}
|
||||
|
||||
|
||||
public boolean isResolvedByHeuristics() throws CoreException {
|
||||
return (getFlag() & FLAG_RESOLVED_BY_HEURISTICS) != 0;
|
||||
}
|
||||
|
||||
public int getNameOffset() throws CoreException {
|
||||
return pdom.getDB().getInt(record + NODE_OFFSET_OFFSET);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ public abstract class AbstractPDOMIndexer implements IPDOMIndexer {
|
|||
|
||||
public AbstractPDOMIndexer() {
|
||||
fProperties.put(IndexerPreferences.KEY_INDEX_ALL_FILES, String.valueOf(false));
|
||||
fProperties.put(IndexerPreferences.KEY_INCLUDE_HEURISTICS, String.valueOf(true));
|
||||
fProperties.put(IndexerPreferences.KEY_FILES_TO_PARSE_UP_FRONT, ""); //$NON-NLS-1$
|
||||
fProperties.put(IndexerPreferences.KEY_SKIP_ALL_REFERENCES, String.valueOf(false));
|
||||
fProperties.put(IndexerPreferences.KEY_SKIP_TYPE_REFERENCES, String.valueOf(false));
|
||||
|
|
|
@ -45,6 +45,7 @@ public class IndexerPreferences {
|
|||
|
||||
public static final String KEY_INDEXER_ID= "indexerId"; //$NON-NLS-1$
|
||||
public static final String KEY_INDEX_ALL_FILES= "indexAllFiles"; //$NON-NLS-1$
|
||||
public static final String KEY_INCLUDE_HEURISTICS= "useHeuristicIncludeResolution"; //$NON-NLS-1$
|
||||
public static final String KEY_FILES_TO_PARSE_UP_FRONT= "filesToParseUpFront"; //$NON-NLS-1$
|
||||
public static final String KEY_SKIP_ALL_REFERENCES= "skipReferences"; //$NON-NLS-1$
|
||||
public static final String KEY_SKIP_TYPE_REFERENCES= "skipTypeReferences"; //$NON-NLS-1$
|
||||
|
@ -156,7 +157,7 @@ public class IndexerPreferences {
|
|||
Preferences[] prefs= getPreferences(project, scope);
|
||||
Properties props= new Properties();
|
||||
for (int i=prefs.length-1; i>=0; i--) {
|
||||
addProperties(prefs[i], props);
|
||||
readProperties(prefs[i], props);
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
@ -164,7 +165,7 @@ public class IndexerPreferences {
|
|||
public static Properties getDefaultIndexerProperties() {
|
||||
Preferences prefs= getDefaultPreferences();
|
||||
Properties props= new Properties();
|
||||
addProperties(prefs, props);
|
||||
readProperties(prefs, props);
|
||||
return props;
|
||||
}
|
||||
|
||||
|
@ -280,7 +281,7 @@ public class IndexerPreferences {
|
|||
return new LocalProjectScope(project).getNode(QUALIFIER).node(INDEXER_NODE);
|
||||
}
|
||||
|
||||
private static void addProperties(Preferences preferences, Properties props) {
|
||||
private static void readProperties(Preferences preferences, Properties props) {
|
||||
try {
|
||||
String[] keys = preferences.keys();
|
||||
for (int i=0; i < keys.length; i++) {
|
||||
|
@ -298,6 +299,7 @@ public class IndexerPreferences {
|
|||
Preferences prefs= defaultPreferences.node(INDEXER_NODE);
|
||||
prefs.put(KEY_INDEXER_ID, IPDOMManager.ID_FAST_INDEXER);
|
||||
prefs.putBoolean(KEY_INDEX_ALL_FILES, false);
|
||||
prefs.putBoolean(KEY_INCLUDE_HEURISTICS, true);
|
||||
prefs.putBoolean(KEY_SKIP_ALL_REFERENCES, false);
|
||||
prefs.putBoolean(KEY_SKIP_TYPE_REFERENCES, false);
|
||||
prefs.putBoolean(KEY_SKIP_MACRO_REFERENCES, false);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2007 QNX Software Systems and others.
|
||||
* Copyright (c) 2006, 2008 QNX Software Systems 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
|
||||
|
@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.core.pdom.indexer;
|
|||
|
||||
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
|
||||
/**
|
||||
* Configures the abstract indexer to return tasks suitable for fast indexing.
|
||||
|
@ -28,4 +29,9 @@ class PDOMFastIndexerTask extends PDOMIndexerTask {
|
|||
protected ICodeReaderFactory createReaderFactory() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIncludeFileResolutionHeuristics createIncludeHeuristics() {
|
||||
return new ProjectIndexerIncludeResolutionHeuristics(getCProject().getProject(), getInputAdapter());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2006, 2007 QNX Software Systems and others.
|
||||
* Copyright (c) 2006, 2008 QNX Software Systems 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
|
||||
|
@ -14,6 +14,7 @@ package org.eclipse.cdt.internal.core.pdom.indexer;
|
|||
|
||||
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
import org.eclipse.cdt.internal.core.dom.SavedCodeReaderFactory;
|
||||
|
||||
|
||||
|
@ -28,6 +29,11 @@ class PDOMFullIndexerTask extends PDOMIndexerTask {
|
|||
|
||||
@Override
|
||||
protected ICodeReaderFactory createReaderFactory() {
|
||||
return SavedCodeReaderFactory.getInstance();
|
||||
return SavedCodeReaderFactory.createInstance(createIncludeHeuristics());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIncludeFileResolutionHeuristics createIncludeHeuristics() {
|
||||
return new ProjectIndexerIncludeResolutionHeuristics(getCProject().getProject(), getInputAdapter());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,130 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.pdom.indexer;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.cdt.core.index.IIndexFileLocation;
|
||||
import org.eclipse.cdt.internal.core.dom.IIncludeFileResolutionHeuristics;
|
||||
import org.eclipse.cdt.internal.core.pdom.ASTFilePathResolver;
|
||||
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
|
||||
/**
|
||||
* Heuristics for picking up includes from the project
|
||||
*/
|
||||
public class ProjectIndexerIncludeResolutionHeuristics implements IIncludeFileResolutionHeuristics {
|
||||
private static final String TRUE = "true"; //$NON-NLS-1$
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
private static final boolean IGNORE_CASE = new File("a").equals(new File("A"));
|
||||
|
||||
private IProject fProject;
|
||||
private IProject[] fProjects;
|
||||
private final ASTFilePathResolver fResolver;
|
||||
|
||||
public ProjectIndexerIncludeResolutionHeuristics(IProject project, ASTFilePathResolver resolver) {
|
||||
fProject= project;
|
||||
fResolver= resolver;
|
||||
}
|
||||
|
||||
public String findInclusion(String include, String currentFile) {
|
||||
final IIndexFileLocation ifl= fResolver.resolveASTPath(currentFile);
|
||||
if (ifl == null || ifl.getFullPath() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (fProject == null)
|
||||
return null;
|
||||
|
||||
|
||||
if (fProjects == null) {
|
||||
if (fProject.isOpen()) {
|
||||
String val= IndexerPreferences.get(fProject, IndexerPreferences.KEY_INCLUDE_HEURISTICS, TRUE);
|
||||
if (TRUE.equals(val)) {
|
||||
fProjects= getOpenReferencedProjects(fProject);
|
||||
}
|
||||
}
|
||||
if (fProjects == null) {
|
||||
fProject= null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IFile[] files= ResourceLookup.findFilesByName(new Path(include), fProjects, IGNORE_CASE);
|
||||
if (files.length == 0)
|
||||
return null;
|
||||
|
||||
return selectBest(files, ifl.getFullPath().toCharArray()).getLocation().toString();
|
||||
}
|
||||
|
||||
|
||||
private IResource selectBest(IFile[] files, char[] currentFullPath) {
|
||||
IFile best= files[0];
|
||||
int bestScore= computeScore(best.getFullPath().toString().toCharArray(), currentFullPath);
|
||||
|
||||
for (int i = 1; i < files.length; i++) {
|
||||
IFile file= files[i];
|
||||
int score= computeScore(file.getFullPath().toString().toCharArray(), currentFullPath);
|
||||
if (score > bestScore) {
|
||||
bestScore= score;
|
||||
best= file;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
private int computeScore(char[] path1, char[] path2) {
|
||||
final int limit= Math.min(path1.length, path2.length);
|
||||
int match=0;
|
||||
for (int i = 0; i < limit; i++) {
|
||||
if (path1[i] != path2[i])
|
||||
break;
|
||||
if (path1[i] == '/')
|
||||
match= i;
|
||||
}
|
||||
// prefer shortest path with longest matches with
|
||||
return (match << 16) - path1.length;
|
||||
}
|
||||
|
||||
private IProject[] getOpenReferencedProjects(IProject prj) {
|
||||
Set<IProject> result= new HashSet<IProject>();
|
||||
|
||||
if (prj.isOpen()) {
|
||||
result.add(prj);
|
||||
|
||||
List<IProject> projectsToSearch= new ArrayList<IProject>();
|
||||
projectsToSearch.add(prj);
|
||||
for (int i=0; i<projectsToSearch.size(); i++) {
|
||||
IProject project= projectsToSearch.get(i);
|
||||
IProject[] nextLevel;
|
||||
try {
|
||||
nextLevel= project.getReferencedProjects();
|
||||
for (IProject prjNextLevel : nextLevel) {
|
||||
if (prjNextLevel.isOpen() && result.add(prjNextLevel)) {
|
||||
projectsToSearch.add(prjNextLevel);
|
||||
}
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toArray(new IProject[result.size()]);
|
||||
}
|
||||
}
|
|
@ -55,6 +55,7 @@ import org.eclipse.cdt.internal.core.model.IBufferFactory;
|
|||
import org.eclipse.cdt.internal.core.model.Util;
|
||||
import org.eclipse.cdt.internal.core.model.WorkingCopy;
|
||||
import org.eclipse.cdt.internal.core.pdom.PDOMManager;
|
||||
import org.eclipse.cdt.internal.core.resources.ResourceLookup;
|
||||
import org.eclipse.cdt.internal.core.settings.model.CProjectDescriptionManager;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IProjectDescription;
|
||||
|
@ -322,6 +323,7 @@ public class CCorePlugin extends Plugin {
|
|||
}
|
||||
|
||||
fNewCProjectDescriptionManager.shutdown();
|
||||
ResourceLookup.shutdown();
|
||||
|
||||
savePluginPreferences();
|
||||
} finally {
|
||||
|
@ -340,7 +342,8 @@ public class CCorePlugin extends Plugin {
|
|||
cdtLog = new CDTLogWriter(CCorePlugin.getDefault().getStateLocation().append(".log").toFile()); //$NON-NLS-1$
|
||||
configurePluginDebugOptions();
|
||||
PositionTrackerManager.getInstance().install();
|
||||
|
||||
ResourceLookup.startup();
|
||||
|
||||
// new project model needs to register the resource listener first.
|
||||
fNewCProjectDescriptionManager= CProjectDescriptionManager.getInstance();
|
||||
final Job post1= fNewCProjectDescriptionManager.startup();
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2004, 2007 IBM Corporation and others.
|
||||
* Copyright (c) 2004, 2008 IBM Corporation 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:
|
||||
* IBM - Initial API and implementation
|
||||
* IBM - Initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.core.dom;
|
||||
import org.eclipse.cdt.core.dom.ast.IASTCompletionNode;
|
||||
|
@ -105,9 +105,9 @@ public class CDOM implements IASTServiceProvider {
|
|||
case PARSE_SAVED_RESOURCES:
|
||||
return SavedCodeReaderFactory.getInstance();
|
||||
case PARSE_WORKING_COPY_WITH_SAVED_INCLUSIONS:
|
||||
return new PartialWorkingCopyCodeReaderFactory( provider );
|
||||
return new PartialWorkingCopyCodeReaderFactory(provider, null);
|
||||
case PARSE_WORKING_COPY_WHENEVER_POSSIBLE:
|
||||
return new WorkingCopyCodeReaderFactory( provider );
|
||||
return new WorkingCopyCodeReaderFactory( provider, null );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom;
|
||||
|
||||
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
|
||||
import org.eclipse.core.runtime.IAdaptable;
|
||||
|
||||
/**
|
||||
* Base implementation for all code reader factories.
|
||||
*/
|
||||
public abstract class AbstractCodeReaderFactory implements ICodeReaderFactory, IAdaptable {
|
||||
|
||||
private final IIncludeFileResolutionHeuristics fHeuristics;
|
||||
|
||||
public AbstractCodeReaderFactory(IIncludeFileResolutionHeuristics heuristics) {
|
||||
fHeuristics= heuristics;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getAdapter(Class adapter) {
|
||||
if (adapter.isAssignableFrom(IIncludeFileResolutionHeuristics.class)) {
|
||||
return fHeuristics;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract base class for heuristic include file resolution.
|
||||
*/
|
||||
public interface IIncludeFileResolutionHeuristics {
|
||||
|
||||
/**
|
||||
* Attempt to find a file for the given include without using an include search path.
|
||||
* @param include the include as provided in the directive
|
||||
* @param currentFile the file the inclusion belongs to.
|
||||
* @return a location for the inclusion or null.
|
||||
*/
|
||||
String findInclusion(String include, String currentFile);
|
||||
}
|
|
@ -19,7 +19,7 @@ import org.eclipse.cdt.core.parser.ICodeReaderCache;
|
|||
*
|
||||
* @since 4.0
|
||||
*/
|
||||
public class NullCodeReaderFactory implements ICodeReaderFactory {
|
||||
public class NullCodeReaderFactory extends AbstractCodeReaderFactory {
|
||||
|
||||
private static final char[] EMPTY_CHARS = new char[0];
|
||||
private static final ICodeReaderFactory INSTANCE= new NullCodeReaderFactory();
|
||||
|
@ -29,7 +29,7 @@ public class NullCodeReaderFactory implements ICodeReaderFactory {
|
|||
}
|
||||
|
||||
private NullCodeReaderFactory() {
|
||||
// singleton
|
||||
super(null);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -14,7 +14,6 @@ import java.util.Arrays;
|
|||
import java.util.Iterator;
|
||||
|
||||
import org.eclipse.cdt.core.dom.CDOM;
|
||||
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.model.IWorkingCopy;
|
||||
import org.eclipse.cdt.core.model.IWorkingCopyProvider;
|
||||
|
@ -26,8 +25,7 @@ import org.eclipse.cdt.internal.core.parser.EmptyIterator;
|
|||
/**
|
||||
* @author jcamelon
|
||||
*/
|
||||
public class PartialWorkingCopyCodeReaderFactory
|
||||
implements ICodeReaderFactory {
|
||||
public class PartialWorkingCopyCodeReaderFactory extends AbstractCodeReaderFactory {
|
||||
|
||||
private final IWorkingCopyProvider provider;
|
||||
private ICodeReaderCache cache = null;
|
||||
|
@ -35,7 +33,8 @@ public class PartialWorkingCopyCodeReaderFactory
|
|||
/**
|
||||
* @param provider
|
||||
*/
|
||||
public PartialWorkingCopyCodeReaderFactory(IWorkingCopyProvider provider) {
|
||||
public PartialWorkingCopyCodeReaderFactory(IWorkingCopyProvider provider, IIncludeFileResolutionHeuristics heuristics) {
|
||||
super(heuristics);
|
||||
this.provider = provider;
|
||||
cache = SavedCodeReaderFactory.getInstance().getCodeReaderCache();
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ package org.eclipse.cdt.internal.core.dom;
|
|||
|
||||
import org.eclipse.cdt.core.CCorePlugin;
|
||||
import org.eclipse.cdt.core.dom.CDOM;
|
||||
import org.eclipse.cdt.core.dom.ICodeReaderFactory;
|
||||
import org.eclipse.cdt.core.model.ITranslationUnit;
|
||||
import org.eclipse.cdt.core.parser.CodeReader;
|
||||
import org.eclipse.cdt.core.parser.CodeReaderCache;
|
||||
|
@ -22,43 +21,49 @@ import org.eclipse.core.runtime.Preferences;
|
|||
/**
|
||||
* @author jcamelon
|
||||
*/
|
||||
public class SavedCodeReaderFactory implements ICodeReaderFactory {
|
||||
public class SavedCodeReaderFactory extends AbstractCodeReaderFactory {
|
||||
|
||||
private ICodeReaderCache cache = null;
|
||||
private static ICodeReaderCache cache;
|
||||
private static SavedCodeReaderFactory instance = new SavedCodeReaderFactory(null);
|
||||
|
||||
public static SavedCodeReaderFactory getInstance()
|
||||
{
|
||||
public static SavedCodeReaderFactory getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private static SavedCodeReaderFactory instance = new SavedCodeReaderFactory();
|
||||
public static SavedCodeReaderFactory createInstance(IIncludeFileResolutionHeuristics heuristics) {
|
||||
return new SavedCodeReaderFactory(heuristics);
|
||||
}
|
||||
|
||||
private SavedCodeReaderFactory()
|
||||
{
|
||||
int size= CodeReaderCache.DEFAULT_CACHE_SIZE_IN_MB;
|
||||
final CCorePlugin corePlugin = CCorePlugin.getDefault();
|
||||
if (corePlugin != null) {
|
||||
Preferences pluginPreferences = corePlugin.getPluginPreferences();
|
||||
if (pluginPreferences != null) {
|
||||
size = pluginPreferences.getInt(CodeReaderCache.CODE_READER_BUFFER);
|
||||
if (size == 0) {
|
||||
String [] properties = pluginPreferences.propertyNames();
|
||||
boolean found = false;
|
||||
for (int j = 0; j < properties.length; ++j) {
|
||||
if (properties[j].equals( CodeReaderCache.CODE_READER_BUFFER)) {
|
||||
found = true;
|
||||
break;
|
||||
|
||||
private SavedCodeReaderFactory(IIncludeFileResolutionHeuristics heuristics) {
|
||||
super(heuristics);
|
||||
|
||||
if (cache == null) {
|
||||
int size= CodeReaderCache.DEFAULT_CACHE_SIZE_IN_MB;
|
||||
final CCorePlugin corePlugin = CCorePlugin.getDefault();
|
||||
if (corePlugin != null) {
|
||||
Preferences pluginPreferences = corePlugin.getPluginPreferences();
|
||||
if (pluginPreferences != null) {
|
||||
size = pluginPreferences.getInt(CodeReaderCache.CODE_READER_BUFFER);
|
||||
if (size == 0) {
|
||||
String [] properties = pluginPreferences.propertyNames();
|
||||
boolean found = false;
|
||||
for (int j = 0; j < properties.length; ++j) {
|
||||
if (properties[j].equals( CodeReaderCache.CODE_READER_BUFFER)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
if (!found) {
|
||||
size= CodeReaderCache.DEFAULT_CACHE_SIZE_IN_MB;
|
||||
}
|
||||
} else if (size < 0) {
|
||||
size= CodeReaderCache.DEFAULT_CACHE_SIZE_IN_MB;
|
||||
}
|
||||
} else if (size < 0) {
|
||||
size= CodeReaderCache.DEFAULT_CACHE_SIZE_IN_MB;
|
||||
}
|
||||
}
|
||||
cache= new CodeReaderCache(size);
|
||||
}
|
||||
cache = new CodeReaderCache(size);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.cdt.core.dom.ICodeReaderFactory#getUniqueIdentifier()
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* IBM - Initial API and implementation
|
||||
* IBM - Initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.dom;
|
||||
|
||||
|
@ -23,8 +23,8 @@ public class WorkingCopyCodeReaderFactory extends PartialWorkingCopyCodeReaderFa
|
|||
/**
|
||||
* @param provider
|
||||
*/
|
||||
public WorkingCopyCodeReaderFactory(IWorkingCopyProvider provider) {
|
||||
super(provider);
|
||||
public WorkingCopyCodeReaderFactory(IWorkingCopyProvider provider, IIncludeFileResolutionHeuristics heuristics) {
|
||||
super(provider, heuristics);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.resources;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
|
||||
/**
|
||||
* Allows for looking up resources by location or name.
|
||||
*/
|
||||
public class ResourceLookup {
|
||||
private static ResourceLookupImpl sInstance= new ResourceLookupImpl();
|
||||
|
||||
public static void startup() {
|
||||
sInstance.startup();
|
||||
}
|
||||
|
||||
public static void shutdown() {
|
||||
sInstance.shutdown();
|
||||
}
|
||||
|
||||
public static IFile[] findFilesForLocation(URI location, IProject[] projects) {
|
||||
return sInstance.findFilesForLocation(location, projects);
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for files with the given location suffix.
|
||||
* @param locationSuffix the suffix to match, always used as relative path.
|
||||
* @param projects the projects to search
|
||||
* @param ignoreCase whether or not to ignore case when comparing the suffix.
|
||||
*/
|
||||
public static IFile[] findFilesByName(IPath locationSuffix, IProject[] projects, boolean ignoreCase) {
|
||||
return sInstance.findFilesByName(locationSuffix, projects, ignoreCase);
|
||||
}
|
||||
|
||||
/**
|
||||
* For testing, only.
|
||||
*/
|
||||
public static void dump() {
|
||||
sInstance.dump();
|
||||
}
|
||||
/**
|
||||
* For testing, only.
|
||||
*/
|
||||
public static void unrefNodeMap() {
|
||||
sInstance.unrefNodeMap();
|
||||
}
|
||||
/**
|
||||
* For testing, only.
|
||||
*/
|
||||
public static void simulateNodeMapCollection() {
|
||||
sInstance.simulateNodeMapCollection();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,809 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2008 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
|
||||
*******************************************************************************/
|
||||
package org.eclipse.cdt.internal.core.resources;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
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.CProjectNature;
|
||||
import org.eclipse.cdt.core.model.CoreModel;
|
||||
import org.eclipse.cdt.core.parser.util.CharArrayUtils;
|
||||
import org.eclipse.core.resources.IFile;
|
||||
import org.eclipse.core.resources.IProject;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.resources.IResourceChangeEvent;
|
||||
import org.eclipse.core.resources.IResourceChangeListener;
|
||||
import org.eclipse.core.resources.IResourceDelta;
|
||||
import org.eclipse.core.resources.IResourceDeltaVisitor;
|
||||
import org.eclipse.core.resources.IResourceProxy;
|
||||
import org.eclipse.core.resources.IResourceProxyVisitor;
|
||||
import org.eclipse.core.resources.IWorkspace;
|
||||
import org.eclipse.core.resources.IWorkspaceRoot;
|
||||
import org.eclipse.core.resources.ResourcesPlugin;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.core.runtime.IPath;
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Path;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.content.IContentType;
|
||||
import org.eclipse.core.runtime.content.IContentTypeManager;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
|
||||
/**
|
||||
* Allows for looking up resources by location or name. When using this class 100 bytes per resource
|
||||
* are needed. Therefore the support is limited to header-files int non-cdt projects and all files
|
||||
* except non-cdt-files in CDT projects.
|
||||
*
|
||||
* The information for a project is initialized when first requested and then it is kept up to date
|
||||
* using a resource change listener. No memory is used, as long as the class is not used.
|
||||
* When information is not used for more than 10 minutes, the data-structures will be held via a weak
|
||||
* reference, only and are subject to garbage collection.
|
||||
*
|
||||
* The node map stores a map from hash-code of file-names to nodes.
|
||||
* A node contains the name of a file plus a link to the parent resource. From that we can compute
|
||||
* the resource path and obtain further information via the resource.
|
||||
*/
|
||||
class ResourceLookupImpl implements IResourceChangeListener, IResourceDeltaVisitor, IResourceProxyVisitor {
|
||||
private static final int UNREF_DELAY = 10 * 60000; // 10 min
|
||||
|
||||
private static final boolean VISIT_CHILDREN = true;
|
||||
private static final boolean SKIP_CHILDREN = false;
|
||||
private static final IFile[] NO_FILES = new IFile[0];
|
||||
private static final int TRIGGER_RECALC=
|
||||
IResourceDelta.TYPE | IResourceDelta.REPLACED |
|
||||
IResourceDelta.LOCAL_CHANGED | IResourceDelta.OPEN;
|
||||
|
||||
private static class Extensions {
|
||||
private final boolean fInvert;
|
||||
private final Set<String> fExtensions;
|
||||
Extensions(Set<String> extensions, boolean invert) {
|
||||
fInvert= invert;
|
||||
fExtensions= extensions;
|
||||
}
|
||||
boolean isRelevant(String filename) {
|
||||
// accept all files without extension
|
||||
final int idx= filename.lastIndexOf('.');
|
||||
if (idx < 0)
|
||||
return true;
|
||||
|
||||
return fExtensions.contains(filename.substring(idx+1)) != fInvert;
|
||||
}
|
||||
}
|
||||
|
||||
private static class Node {
|
||||
final Node fParent;
|
||||
final char[] fResourceName;
|
||||
final boolean fIsFolder;
|
||||
|
||||
boolean fDeleted;
|
||||
boolean fHasChildren;
|
||||
private int fCanonicHash;
|
||||
|
||||
Node(Node parent, char[] name, boolean isFolder) {
|
||||
fParent= parent;
|
||||
fResourceName= name;
|
||||
fIsFolder= isFolder;
|
||||
if (parent != null)
|
||||
parent.fHasChildren= true;
|
||||
}
|
||||
}
|
||||
|
||||
private final Object fLock= new Object();
|
||||
private final Job fUnrefJob;
|
||||
private SoftReference<Map<Integer, Object>> fNodeMapRef;
|
||||
private Map<Integer, Object> fNodeMap;
|
||||
private final Map<String, Extensions> fFileExtensions;
|
||||
private Extensions fCDTProjectExtensions;
|
||||
private Extensions fDefaultExtensions;
|
||||
private Extensions fCurrentExtensions;
|
||||
private Node fRootNode;
|
||||
private boolean fNeedCleanup;
|
||||
private Node fLastFolderNode;
|
||||
|
||||
public ResourceLookupImpl() {
|
||||
fRootNode= new Node(null, CharArrayUtils.EMPTY, true) {};
|
||||
fFileExtensions= new HashMap<String, Extensions>();
|
||||
fUnrefJob= new Job("Timer") { //$NON-NLS-1$
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
unrefNodeMap();
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
};
|
||||
fUnrefJob.setSystem(true);
|
||||
}
|
||||
|
||||
public void startup() {
|
||||
final IWorkspace workspace = ResourcesPlugin.getWorkspace();
|
||||
workspace.addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
|
||||
synchronized (fLock) {
|
||||
fNodeMap= null;
|
||||
fNodeMapRef= null;
|
||||
fFileExtensions.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle resource change notifications.
|
||||
*/
|
||||
public void resourceChanged(IResourceChangeEvent event) {
|
||||
IResourceDelta delta= event.getDelta();
|
||||
synchronized (fLock) {
|
||||
if (fNodeMapRef == null)
|
||||
return;
|
||||
boolean unsetMap= false;
|
||||
if (fNodeMap == null) {
|
||||
fNodeMap= fNodeMapRef.get();
|
||||
if (fNodeMap == null)
|
||||
return;
|
||||
unsetMap= true;
|
||||
}
|
||||
try {
|
||||
delta.accept(this);
|
||||
} catch (CoreException e) {
|
||||
CCorePlugin.log(e);
|
||||
} finally {
|
||||
if (fNeedCleanup)
|
||||
cleanup();
|
||||
fCurrentExtensions= null;
|
||||
fNeedCleanup= false;
|
||||
if (unsetMap)
|
||||
fNodeMap= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles resource change notifications by visiting the delta.
|
||||
*/
|
||||
public boolean visit(IResourceDelta delta) throws CoreException {
|
||||
assert Thread.holdsLock(fLock);
|
||||
|
||||
final IResource res= delta.getResource();
|
||||
if (res instanceof IWorkspaceRoot)
|
||||
return VISIT_CHILDREN;
|
||||
|
||||
if (res instanceof IProject) {
|
||||
// project not yet handled
|
||||
final String name = res.getName();
|
||||
final Extensions exts= fFileExtensions.get(name);
|
||||
if (exts == null)
|
||||
return SKIP_CHILDREN;
|
||||
|
||||
switch (delta.getKind()) {
|
||||
case IResourceDelta.ADDED: // new projects should not yet be part of the tree
|
||||
case IResourceDelta.REMOVED:
|
||||
fFileExtensions.remove(name);
|
||||
remove(res);
|
||||
return SKIP_CHILDREN;
|
||||
|
||||
case IResourceDelta.CHANGED:
|
||||
if ((delta.getFlags() & (TRIGGER_RECALC | IResourceDelta.DESCRIPTION)) != 0) {
|
||||
fFileExtensions.remove(name);
|
||||
remove(res);
|
||||
return SKIP_CHILDREN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
fCurrentExtensions= exts;
|
||||
return VISIT_CHILDREN;
|
||||
}
|
||||
|
||||
// file or folder
|
||||
switch (delta.getKind()) {
|
||||
case IResourceDelta.ADDED:
|
||||
add(res);
|
||||
return SKIP_CHILDREN;
|
||||
|
||||
case IResourceDelta.CHANGED:
|
||||
if ((delta.getFlags() & TRIGGER_RECALC) != 0) {
|
||||
remove(res);
|
||||
add(res);
|
||||
return SKIP_CHILDREN;
|
||||
}
|
||||
return VISIT_CHILDREN;
|
||||
|
||||
case IResourceDelta.REMOVED:
|
||||
|
||||
remove(res);
|
||||
return SKIP_CHILDREN;
|
||||
}
|
||||
return VISIT_CHILDREN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a resource to the tree.
|
||||
*/
|
||||
private void add(IResource res) {
|
||||
assert Thread.holdsLock(fLock);
|
||||
|
||||
if (res instanceof IFile) {
|
||||
if (fCurrentExtensions.isRelevant(res.getName())) {
|
||||
createFileNode(res.getFullPath());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
res.accept(this, 0);
|
||||
} catch (CoreException e) {
|
||||
CCorePlugin.log(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a resource tree by using a resource proxy visitor.
|
||||
*/
|
||||
public boolean visit(IResourceProxy proxy) throws CoreException {
|
||||
if (proxy.getType() == IResource.FILE) {
|
||||
if (fCurrentExtensions.isRelevant(proxy.getName())) {
|
||||
createFileNode(proxy.requestFullPath());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void unrefNodeMap() {
|
||||
synchronized (fLock) {
|
||||
fNodeMap= null;
|
||||
}
|
||||
}
|
||||
|
||||
public void simulateNodeMapCollection() {
|
||||
synchronized (fLock) {
|
||||
fNodeMap= null;
|
||||
fNodeMapRef= new SoftReference<Map<Integer, Object>>(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes nodes for the given projects. Also creates the node map if it was collected.
|
||||
*/
|
||||
private void initializeProjects(IProject[] projects) {
|
||||
assert Thread.holdsLock(fLock);
|
||||
|
||||
if (fNodeMap == null) {
|
||||
if (fNodeMapRef != null) {
|
||||
fNodeMap= fNodeMapRef.get();
|
||||
}
|
||||
|
||||
if (fNodeMap == null) {
|
||||
fFileExtensions.clear();
|
||||
fNodeMap= new HashMap<Integer, Object>();
|
||||
fNodeMapRef= new SoftReference<Map<Integer, Object>>(fNodeMap);
|
||||
}
|
||||
}
|
||||
fUnrefJob.cancel();
|
||||
fUnrefJob.schedule(UNREF_DELAY);
|
||||
|
||||
for (IProject project : projects) {
|
||||
if (project.isOpen() && !fFileExtensions.containsKey(project.getName())) {
|
||||
Extensions ext= fDefaultExtensions;
|
||||
try {
|
||||
if (project.hasNature(CProjectNature.C_NATURE_ID)) {
|
||||
ext= fCDTProjectExtensions;
|
||||
}
|
||||
} catch (CoreException e) {
|
||||
CCorePlugin.log(e);
|
||||
// treat as non-cdt project
|
||||
}
|
||||
fCurrentExtensions= ext;
|
||||
add(project);
|
||||
fFileExtensions.put(project.getName(), ext);
|
||||
fCurrentExtensions= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes file-extensions and node map
|
||||
*/
|
||||
private void initFileExtensions() {
|
||||
if (fDefaultExtensions == null) {
|
||||
HashSet<String> select= new HashSet<String>();
|
||||
String[] registeredContentTypes= CoreModel.getRegistedContentTypeIds();
|
||||
select.addAll(Arrays.asList(registeredContentTypes));
|
||||
|
||||
final IContentTypeManager ctm= Platform.getContentTypeManager();
|
||||
final IContentType[] ctts= ctm.getAllContentTypes();
|
||||
Set<String> result= new HashSet<String>();
|
||||
outer: for (IContentType ctt : ctts) {
|
||||
IContentType basedOn= ctt;
|
||||
while (basedOn != null) {
|
||||
if (select.contains(basedOn.getId()))
|
||||
continue outer;
|
||||
basedOn= basedOn.getBaseType();
|
||||
}
|
||||
// this is a non-cdt content type
|
||||
String[] fspecs= ctt.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
|
||||
result.addAll(Arrays.asList(fspecs));
|
||||
}
|
||||
fCDTProjectExtensions= new Extensions(result, true);
|
||||
|
||||
result= new HashSet<String>();
|
||||
select.clear();
|
||||
select.add(CCorePlugin.CONTENT_TYPE_CHEADER);
|
||||
select.add(CCorePlugin.CONTENT_TYPE_CXXHEADER);
|
||||
for (IContentType ctt : ctts) {
|
||||
IContentType basedOn= ctt;
|
||||
boolean selectme= false;
|
||||
while (basedOn != null) {
|
||||
if (select.contains(basedOn.getId())) {
|
||||
selectme= true;
|
||||
break;
|
||||
}
|
||||
basedOn= basedOn.getBaseType();
|
||||
}
|
||||
if (selectme) {
|
||||
// this is content type for a header file
|
||||
String[] fspecs= ctt.getFileSpecs(IContentType.FILE_EXTENSION_SPEC);
|
||||
result.addAll(Arrays.asList(fspecs));
|
||||
}
|
||||
}
|
||||
fDefaultExtensions= new Extensions(result, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a node for the given path.
|
||||
*/
|
||||
private void createFileNode(IPath fullPath) {
|
||||
final String[] segments= fullPath.segments();
|
||||
createNode(toCharArrayArray(segments), segments.length, false);
|
||||
}
|
||||
|
||||
private char[][] toCharArrayArray(String[] segments) {
|
||||
final int len= segments.length;
|
||||
char[][] chsegs= new char[len][];
|
||||
for (int i = 0; i < segments.length; i++) {
|
||||
chsegs[i]= segments[i].toCharArray();
|
||||
}
|
||||
return chsegs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a node for the given path.
|
||||
*/
|
||||
private Node createNode(char[][] segments, int segmentCount, boolean folder) {
|
||||
assert Thread.holdsLock(fLock);
|
||||
|
||||
if (segmentCount == 0)
|
||||
return fRootNode;
|
||||
|
||||
if (folder && fLastFolderNode != null) {
|
||||
if (isNodeForSegments(fLastFolderNode, segments, segmentCount))
|
||||
return fLastFolderNode;
|
||||
}
|
||||
|
||||
final char[] name= segments[segmentCount-1];
|
||||
final int hash= hashCode(name);
|
||||
|
||||
// search for existing node
|
||||
Object obj= fNodeMap.get(hash);
|
||||
|
||||
Node[] nodes= null;
|
||||
int len= 0;
|
||||
if (obj != null) {
|
||||
if (obj instanceof Node) {
|
||||
Node node= (Node) obj;
|
||||
if (isNodeForSegments(node, segments, segmentCount)) {
|
||||
if (folder)
|
||||
fLastFolderNode= node;
|
||||
return node;
|
||||
}
|
||||
nodes= new Node[]{node, null};
|
||||
fNodeMap.put(hash, nodes);
|
||||
len= 1;
|
||||
} else {
|
||||
nodes= (Node[]) obj;
|
||||
for (len=0; len < nodes.length; len++) {
|
||||
Node node = nodes[len];
|
||||
if (node == null)
|
||||
break;
|
||||
if (isNodeForSegments(node, segments, segmentCount)) {
|
||||
if (folder)
|
||||
fLastFolderNode= node;
|
||||
return node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final Node parent= createNode(segments, segmentCount-1, true);
|
||||
Node node= new Node(parent, name, folder);
|
||||
if (nodes == null) {
|
||||
fNodeMap.put(hash, node);
|
||||
} else {
|
||||
if (len == nodes.length) {
|
||||
Node[] newNodes= new Node[len+2];
|
||||
System.arraycopy(nodes, 0, newNodes, 0, len);
|
||||
nodes= newNodes;
|
||||
fNodeMap.put(hash, nodes);
|
||||
}
|
||||
nodes[len]= node;
|
||||
}
|
||||
|
||||
if (folder)
|
||||
fLastFolderNode= node;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given node matches the given segments.
|
||||
*/
|
||||
private boolean isNodeForSegments(Node node, char[][] segments, int segmentLength) {
|
||||
assert Thread.holdsLock(fLock);
|
||||
|
||||
while(segmentLength > 0 && node != null) {
|
||||
if (!CharArrayUtils.equals(segments[--segmentLength], node.fResourceName))
|
||||
return false;
|
||||
node= node.fParent;
|
||||
}
|
||||
return node == fRootNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a resource from the tree
|
||||
*/
|
||||
private void remove(IResource res) {
|
||||
assert Thread.holdsLock(fLock);
|
||||
|
||||
final char[] name= res.getName().toCharArray();
|
||||
final int hash= hashCode(name);
|
||||
|
||||
Object obj= fNodeMap.get(hash);
|
||||
if (obj == null)
|
||||
return;
|
||||
|
||||
final IPath fullPath= res.getFullPath();
|
||||
final int segmentCount= fullPath.segmentCount();
|
||||
if (segmentCount == 0)
|
||||
return;
|
||||
|
||||
final char[][]segments= toCharArrayArray(fullPath.segments());
|
||||
if (obj instanceof Node) {
|
||||
final Node node= (Node) obj;
|
||||
if (!node.fDeleted && isNodeForSegments(node, segments, segmentCount)) {
|
||||
node.fDeleted= true;
|
||||
if (node.fHasChildren)
|
||||
fNeedCleanup= true;
|
||||
fNodeMap.remove(hash);
|
||||
}
|
||||
} else {
|
||||
final Node[] nodes= (Node[]) obj;
|
||||
for (int i= 0; i < nodes.length; i++) {
|
||||
Node node = nodes[i];
|
||||
if (node == null)
|
||||
return;
|
||||
if (!node.fDeleted && isNodeForSegments(node, segments, segmentCount)) {
|
||||
remove(nodes, i);
|
||||
|
||||
if (nodes[0] == null)
|
||||
fNodeMap.remove(hash);
|
||||
|
||||
node.fDeleted= true;
|
||||
if (node.fHasChildren)
|
||||
fNeedCleanup= true;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void remove(Node[] nodes, int i) {
|
||||
int idx= lastValid(nodes, i);
|
||||
if (idx > 0) {
|
||||
nodes[i]= nodes[idx];
|
||||
nodes[idx]= null;
|
||||
}
|
||||
}
|
||||
|
||||
private int lastValid(Node[] nodes, int left) {
|
||||
int right= nodes.length-1;
|
||||
while (left < right) {
|
||||
int mid= (left+right+1)/2; // ==> mid > left
|
||||
if (nodes[mid] == null)
|
||||
right= mid-1;
|
||||
else
|
||||
left= mid;
|
||||
}
|
||||
return right;
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
assert Thread.holdsLock(fLock);
|
||||
fLastFolderNode= null;
|
||||
|
||||
for (Iterator<Object> iterator = fNodeMap.values().iterator(); iterator.hasNext();) {
|
||||
Object obj= iterator.next();
|
||||
if (obj instanceof Node) {
|
||||
if (isDeleted((Node) obj)) {
|
||||
iterator.remove();
|
||||
}
|
||||
} else {
|
||||
Node[] nodes= (Node[]) obj;
|
||||
int j= 0;
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
final Node node = nodes[i];
|
||||
if (node == null) {
|
||||
if (j==0) {
|
||||
iterator.remove();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!isDeleted(node)) {
|
||||
if (i != j) {
|
||||
nodes[j]= node;
|
||||
nodes[i]= null;
|
||||
}
|
||||
j++;
|
||||
} else {
|
||||
nodes[i]= null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDeleted(Node node) {
|
||||
while(node != null) {
|
||||
if (node.fDeleted)
|
||||
return true;
|
||||
node= node.fParent;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a case insensitive hash-code for file names.
|
||||
*/
|
||||
private int hashCode(char[] name) {
|
||||
int h= 0;
|
||||
final int len = name.length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
h = 31*h + Character.toUpperCase(name[i]);
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches for all files with the given location.
|
||||
*/
|
||||
public IFile[] findFilesForLocation(URI location, IProject[] projects) {
|
||||
initFileExtensions();
|
||||
String name= extractName(location);
|
||||
Node[] candidates;
|
||||
synchronized (fLock) {
|
||||
initializeProjects(projects);
|
||||
Object obj= fNodeMap.get(hashCode(name.toCharArray()));
|
||||
if (obj == null) {
|
||||
return NO_FILES;
|
||||
}
|
||||
candidates= convert(obj);
|
||||
}
|
||||
return extractMatchesForLocation(candidates, location);
|
||||
}
|
||||
|
||||
private Node[] convert(Object obj) {
|
||||
if (obj instanceof Node)
|
||||
return new Node[] {(Node) obj};
|
||||
|
||||
final Node[] nodes= (Node[]) obj;
|
||||
final int len= lastValid(nodes, -1)+1;
|
||||
final Node[] result= new Node[len];
|
||||
System.arraycopy(nodes, 0, result, 0, len);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of files for the given name. Search is limited to the supplied projects.
|
||||
*/
|
||||
public IFile[] findFilesByName(IPath relativeLocation, IProject[] projects, boolean ignoreCase) {
|
||||
final int segCount= relativeLocation.segmentCount();
|
||||
if (segCount < 1)
|
||||
return NO_FILES;
|
||||
|
||||
final String name= relativeLocation.lastSegment();
|
||||
Node[] candidates;
|
||||
|
||||
initFileExtensions();
|
||||
synchronized (fLock) {
|
||||
initializeProjects(projects);
|
||||
Object obj= fNodeMap.get(hashCode(name.toCharArray()));
|
||||
if (obj == null) {
|
||||
return NO_FILES;
|
||||
}
|
||||
candidates= convert(obj);
|
||||
}
|
||||
String suffix= relativeLocation.toString();
|
||||
while(suffix.startsWith("../")) { //$NON-NLS-1$
|
||||
suffix= suffix.substring(3);
|
||||
}
|
||||
return extractMatchesForName(candidates, name, suffix, ignoreCase);
|
||||
}
|
||||
|
||||
private String extractName(URI location) {
|
||||
String path= location.getPath();
|
||||
int idx= path.lastIndexOf('/');
|
||||
return path.substring(idx+1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the actual matches for the list of candidate nodes.
|
||||
*/
|
||||
private IFile[] extractMatchesForName(Node[] candidates, String name, String suffix, boolean ignoreCase) {
|
||||
final char[] n1= name.toCharArray();
|
||||
final int namelen = n1.length;
|
||||
int resultIdx= 0;
|
||||
|
||||
if (ignoreCase) {
|
||||
for (int j = 0; j < namelen; j++) {
|
||||
n1[j]= Character.toUpperCase(n1[j]);
|
||||
}
|
||||
}
|
||||
final int suffixLen= suffix.length();
|
||||
final IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot();
|
||||
IFile[] result= null;
|
||||
outer: for (int i = 0; i < candidates.length; i++) {
|
||||
final Node node = candidates[i];
|
||||
if (!node.fIsFolder) {
|
||||
final char[] n2= node.fResourceName;
|
||||
if (namelen == n2.length) {
|
||||
for (int j = 0; j < n2.length; j++) {
|
||||
final char c= ignoreCase ? Character.toUpperCase(n2[j]) : n2[j];
|
||||
if (c != n1[j])
|
||||
continue outer;
|
||||
}
|
||||
final IFile file= root.getFile(createPath(node));
|
||||
final URI loc= file.getLocationURI();
|
||||
if (loc != null) {
|
||||
String path= loc.getPath();
|
||||
final int len= path.length();
|
||||
if (len >= suffixLen &&
|
||||
suffix.regionMatches(ignoreCase, 0, path, len-suffixLen, suffixLen)) {
|
||||
if (result == null)
|
||||
result= new IFile[candidates.length-i];
|
||||
result[resultIdx++]= root.getFile(createPath(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result==null)
|
||||
return NO_FILES;
|
||||
|
||||
if (resultIdx < result.length) {
|
||||
IFile[] copy= new IFile[resultIdx];
|
||||
System.arraycopy(result, 0, copy, 0, resultIdx);
|
||||
return copy;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private IPath createPath(Node node) {
|
||||
if (node == fRootNode)
|
||||
return Path.ROOT;
|
||||
|
||||
return createPath(node.fParent).append(new String(node.fResourceName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the actual matches from the list of candidates
|
||||
*/
|
||||
private IFile[] extractMatchesForLocation(Node[] candidates, URI location) {
|
||||
final IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot();
|
||||
final String searchPath= getCanonicalPath(location);
|
||||
IFile[] result= null;
|
||||
int resultIdx= 0;
|
||||
for (int i = 0; i < candidates.length; i++) {
|
||||
final Node node = candidates[i];
|
||||
if (!node.fIsFolder) {
|
||||
final IFile file= root.getFile(createPath(node));
|
||||
final URI loc= file.getLocationURI();
|
||||
if (loc != null) {
|
||||
if (!loc.equals(location)) {
|
||||
if (searchPath == null)
|
||||
continue;
|
||||
|
||||
if (node.fCanonicHash != 0 && node.fCanonicHash != searchPath.hashCode())
|
||||
continue;
|
||||
|
||||
final String candPath= getCanonicalPath(loc);
|
||||
if (candPath == null)
|
||||
continue;
|
||||
|
||||
node.fCanonicHash= candPath.hashCode();
|
||||
if (!candPath.equals(searchPath))
|
||||
continue;
|
||||
}
|
||||
if (result == null)
|
||||
result= new IFile[candidates.length-i];
|
||||
result[resultIdx++]= root.getFile(createPath(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result==null)
|
||||
return NO_FILES;
|
||||
|
||||
if (resultIdx < result.length) {
|
||||
IFile[] copy= new IFile[resultIdx];
|
||||
System.arraycopy(result, 0, copy, 0, resultIdx);
|
||||
return copy;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getCanonicalPath(URI location) {
|
||||
if (!"file".equals(location.getScheme())) //$NON-NLS-1$
|
||||
return null;
|
||||
|
||||
String path= location.getPath();
|
||||
try {
|
||||
path= new File(path).getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
// use non-canonical version
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
public void dump() {
|
||||
List<String> lines= new ArrayList<String>();
|
||||
synchronized (fLock) {
|
||||
for (Iterator<Object> iterator = fNodeMap.values().iterator(); iterator.hasNext();) {
|
||||
Node[] nodes= convert(iterator.next());
|
||||
for (int i = 0; i < nodes.length; i++) {
|
||||
final Node node = nodes[i];
|
||||
if (node == null) {
|
||||
break;
|
||||
}
|
||||
lines.add(toString(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
Collections.sort(lines);
|
||||
System.out.println("Dumping files:");
|
||||
for (Iterator<String> iterator = lines.iterator(); iterator.hasNext();) {
|
||||
String line = iterator.next();
|
||||
System.out.println(line);
|
||||
}
|
||||
System.out.flush();
|
||||
}
|
||||
|
||||
@SuppressWarnings("nls")
|
||||
private String toString(Node node) {
|
||||
if (node == fRootNode)
|
||||
return "";
|
||||
|
||||
return toString(node.fParent) + "/" + new String(node.fResourceName);
|
||||
}
|
||||
}
|
|
@ -36,6 +36,7 @@ public abstract class AbstractIndexerPage extends AbstractCOptionPage {
|
|||
protected static final String TRUE = String.valueOf(true);
|
||||
|
||||
private Button fAllFiles;
|
||||
private Button fIncludeHeuristics;
|
||||
private Text fFilesToParseUpFront;
|
||||
private Button fSkipReferences;
|
||||
private Button fSkipTypeReferences;
|
||||
|
@ -57,6 +58,7 @@ public abstract class AbstractIndexerPage extends AbstractCOptionPage {
|
|||
public void createControl(Composite parent) {
|
||||
Composite page = ControlFactory.createComposite(parent, 1);
|
||||
fAllFiles= createAllFilesButton(page);
|
||||
fIncludeHeuristics= createIncludeHeuristicsButton(page);
|
||||
fSkipReferences= createSkipReferencesButton(page);
|
||||
fSkipTypeReferences= createSkipTypeReferencesButton(page);
|
||||
fSkipMacroReferences= createSkipMacroReferencesButton(page);
|
||||
|
@ -81,6 +83,11 @@ public abstract class AbstractIndexerPage extends AbstractCOptionPage {
|
|||
boolean indexAllFiles= TRUE.equals(properties.get(IndexerPreferences.KEY_INDEX_ALL_FILES));
|
||||
fAllFiles.setSelection(indexAllFiles);
|
||||
}
|
||||
if (fIncludeHeuristics != null) {
|
||||
Object prop= properties.get(IndexerPreferences.KEY_INCLUDE_HEURISTICS);
|
||||
boolean use= prop == null || TRUE.equals(prop);
|
||||
fIncludeHeuristics.setSelection(use);
|
||||
}
|
||||
if (fSkipReferences != null) {
|
||||
boolean skipReferences= TRUE.equals(properties.get(IndexerPreferences.KEY_SKIP_ALL_REFERENCES));
|
||||
fSkipReferences.setSelection(skipReferences);
|
||||
|
@ -109,6 +116,9 @@ public abstract class AbstractIndexerPage extends AbstractCOptionPage {
|
|||
if (fAllFiles != null) {
|
||||
props.put(IndexerPreferences.KEY_INDEX_ALL_FILES, String.valueOf(fAllFiles.getSelection()));
|
||||
}
|
||||
if (fIncludeHeuristics != null) {
|
||||
props.put(IndexerPreferences.KEY_INCLUDE_HEURISTICS, String.valueOf(fIncludeHeuristics.getSelection()));
|
||||
}
|
||||
if (fFilesToParseUpFront != null) {
|
||||
props.put(IndexerPreferences.KEY_FILES_TO_PARSE_UP_FRONT, fFilesToParseUpFront.getText());
|
||||
}
|
||||
|
@ -168,7 +178,11 @@ public abstract class AbstractIndexerPage extends AbstractCOptionPage {
|
|||
private Button createAllFilesButton(Composite page) {
|
||||
return ControlFactory.createCheckBox(page, INDEX_ALL_FILES);
|
||||
}
|
||||
|
||||
|
||||
private Button createIncludeHeuristicsButton(Composite page) {
|
||||
return ControlFactory.createCheckBox(page, DialogsMessages.AbstractIndexerPage_heuristicIncludes);
|
||||
}
|
||||
|
||||
private Button createSkipReferencesButton(Composite page) {
|
||||
return ControlFactory.createCheckBox(page, DialogsMessages.AbstractIndexerPage_skipAllReferences);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,10 @@ import org.eclipse.osgi.util.NLS;
|
|||
|
||||
public class DialogsMessages extends NLS {
|
||||
private static final String BUNDLE_NAME = "org.eclipse.cdt.ui.dialogs.DialogsMessages"; //$NON-NLS-1$
|
||||
/**
|
||||
* @since 5.1
|
||||
*/
|
||||
public static String AbstractIndexerPage_heuristicIncludes;
|
||||
public static String AbstractIndexerPage_indexAllFiles;
|
||||
public static String AbstractIndexerPage_indexUpFront;
|
||||
public static String AbstractIndexerPage_skipAllReferences;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
PreferenceScopeBlock_enableProjectSettings=Enable project specific settings
|
||||
PreferenceScopeBlock_storeWithProject=Store settings with project
|
||||
PreferenceScopeBlock_preferenceLink=<a>Configure Workspace Settings...</a>
|
||||
AbstractIndexerPage_heuristicIncludes=Allow heuristic resolution of includes
|
||||
AbstractIndexerPage_indexAllFiles=Index all files (files neither built nor included, also)
|
||||
AbstractIndexerPage_skipAllReferences=Skip all references (Call Hierarchy and Search will not work)
|
||||
AbstractIndexerPage_skipTypeReferences=Skip type references (Search for type references will not work)
|
||||
|
|
Loading…
Add table
Reference in a new issue