diff --git a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java index 817bbcb7821..6360bfeccec 100644 --- a/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java +++ b/core/org.eclipse.cdt.core.tests/parser/org/eclipse/cdt/internal/pdom/tests/IncludesTests.java @@ -6,7 +6,8 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * QNX - Initial API and implementation + * QNX - Initial API and implementation + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.pdom.tests; @@ -21,13 +22,12 @@ import org.eclipse.cdt.core.index.IndexLocationFactory; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Path; /** * @author Doug Schaefer - * */ public class IncludesTests extends PDOMTestBase { - protected ICProject project; protected IIndex index; @@ -49,7 +49,7 @@ public class IncludesTests extends PDOMTestBase { public void testIncludedBy() throws Exception { IResource loc = project.getProject().findMember("I2.h"); - IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile)loc)); + IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile) loc)); assertNotNull(file); IIndexInclude[] allIncludedBy = index.findIncludedBy(file, -1); assertEquals(9, allIncludedBy.length); // i.e. all of them @@ -57,9 +57,41 @@ public class IncludesTests extends PDOMTestBase { public void testIncludes() throws Exception { IResource loc = project.getProject().findMember("I1.cpp"); - IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile)loc)); + IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile) loc)); assertNotNull(file); IIndexInclude[] allIncludesTo= index.findIncludes(file, -1); assertEquals(2, allIncludesTo.length); // i.e. I1.h, I2.h } + + public void testIncludeName() throws Exception { + IResource loc = project.getProject().findMember("a/b/I6.h"); + IIndexFile file = index.getFile(ILinkage.CPP_LINKAGE_ID, IndexLocationFactory.getWorkspaceIFL((IFile) loc)); + assertNotNull(file); + IIndexInclude[] allIncludedBy = index.findIncludedBy(file, -1); + assertEquals(2, allIncludedBy.length); + for (IIndexInclude include : allIncludedBy) { + assertTrue(include.isResolved()); + assertFalse(include.isSystemInclude()); + IIndexFile includer = include.getIncludedBy(); + String includerName = new Path(includer.getLocation().getFullPath()).lastSegment(); + if ("I6.cpp".equals(includerName)) { + assertEquals("I6.h", include.getName()); + assertEquals("a/b/I6.h", include.getFullName()); + } else { + assertEquals("I7.cpp", includerName); + assertEquals("I6.h", include.getName()); + assertEquals("b/I6.h", include.getFullName()); + IIndexInclude[] includes = includer.getIncludes(); + for (IIndexInclude include2 : includes) { + if ("I7.h".equals(include2.getName())) { + assertFalse(include2.isResolved()); + assertFalse(include2.isSystemInclude()); + assertEquals("b/I7.h", include2.getFullName()); + } else { + assertEquals("I6.h", include2.getName()); + } + } + } + } + } } diff --git a/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/I6.cpp b/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/I6.cpp new file mode 100644 index 00000000000..b3cca558f9f --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/I6.cpp @@ -0,0 +1 @@ +#include "a/b/I6.h" diff --git a/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/a/I7.cpp b/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/a/I7.cpp new file mode 100644 index 00000000000..6a4cc77fb23 --- /dev/null +++ b/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/a/I7.cpp @@ -0,0 +1,2 @@ +#include "b/I6.h" +#include "b/I7.h" diff --git a/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/a/b/I6.h b/core/org.eclipse.cdt.core.tests/resources/pdomtests/includesTests/a/b/I6.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java index 5cb449d4d17..1cc4cd9f632 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/core/index/IIndexInclude.java @@ -8,6 +8,7 @@ * Contributors: * Markus Schorn - initial API and implementation * Andrew Ferguson (Symbian) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.core.index; @@ -57,8 +58,16 @@ public interface IIndexInclude { String getName() throws CoreException; /** - * Returns the character offset of the name of the include in its source file. The name does - * not include the enclosing quotes or angle brackets. + * Returns the name of the include. The name does not include the enclosing quotes + * or angle brackets. E.g.: for '' 'sys/types.h' will be returned. + * @throws CoreException + * @since 5.1 + */ + String getFullName() throws CoreException; + + /** + * Returns the character offset of the name of the include in its source file. + * The name does not include the enclosing quotes or angle brackets. * @throws CoreException */ int getNameOffset() throws CoreException; diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java index 9ab95d1aecc..4bb170558f2 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/PDOM.java @@ -173,11 +173,12 @@ public class PDOM extends PlatformObject implements IPDOM { * 80.0 - support for specializations of partial specializations, bug 259872 * 81.0 - change to c++ function types, bug 264479 * 82.0 - offsets for using directives, bug 270806 + * 83.0 - unconditionally store name in PROMInclude, bug 272815 */ private static int version(int major, int minor) { return major << 16 + minor; } - public static final int MAJOR_VERSION = 82; + public static final int MAJOR_VERSION = 83; public static final int MINOR_VERSION = 0; // minor versions must be compatible public static final int CURRENT_VERSION= version(MAJOR_VERSION, MINOR_VERSION); diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java index 3034d9cfd9f..8b05142e3e9 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/dom/PDOMInclude.java @@ -6,8 +6,9 @@ * http://www.eclipse.org/legal/epl-v10.html * * Contributors: - * QNX - Initial API and implementation - * Markus Schorn (Wind River Systems) + * QNX - Initial API and implementation + * Markus Schorn (Wind River Systems) + * Sergey Prigogin (Google) *******************************************************************************/ package org.eclipse.cdt.internal.core.pdom.dom; @@ -21,158 +22,172 @@ import org.eclipse.cdt.internal.core.index.IIndexFragment; import org.eclipse.cdt.internal.core.index.IIndexFragmentFile; import org.eclipse.cdt.internal.core.index.IIndexFragmentInclude; import org.eclipse.cdt.internal.core.pdom.db.Database; -import org.eclipse.cdt.internal.core.pdom.db.IString; import org.eclipse.core.runtime.CoreException; /** * @author Doug Schaefer - * */ public class PDOMInclude implements IIndexFragmentInclude { - private static final int INCLUDES_FILE_OR_NAME = 0; - private static final int INCLUDED_BY = 4; - private static final int INCLUDES_NEXT = 8; + private static final int INCLUDED_FILE = 0; + private static final int INCLUDED_BY = 4; + private static final int INCLUDES_NEXT = 8; private static final int INCLUDED_BY_NEXT = 12; private static final int INCLUDED_BY_PREV = 16; - private static final int NODE_OFFSET_OFFSET = 20; - private static final int NODE_LENGTH_OFFSET = 24; - private static final int FLAG_OFFSET = 26; - private static final int RECORD_SIZE = 27; + // If the include name is the same as the end part of the path of the included file, + // we store the length of the name instead of the name itself, and indicate that + // by turning on FLAG_DEDUCIBLE_NAME flag. Notice that the length of include name + // can be different from the node length, if the name is defined by a macro. + private static final int INCLUDE_NAME_OR_LENGTH = 20; + private static final int NODE_OFFSET = 24; // 3-byte unsigned int (sufficient for files <= 16mb) + private static final int NODE_LENGTH = 27; // short (sufficient for names <= 32k) + private static final int FLAGS = 29; + private static final int RECORD_SIZE = 30; - 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 static final int FLAG_SYSTEM_INCLUDE = 0x01; + private static final int FLAG_INACTIVE_INCLUDE = 0x02; + private static final int FLAG_RESOLVED_BY_HEURISTICS= 0x04; + private static final int FLAG_DEDUCIBLE_NAME = 0x08; private final PDOMLinkage linkage; private final int record; - - // cached fields - private String fName= null; + + // Cached fields + private String fName; public PDOMInclude(PDOMLinkage pdom, int record) { this.linkage = pdom; this.record = record; } - - public PDOMInclude(PDOMLinkage linkage, IASTPreprocessorIncludeStatement include, PDOMFile containerFile, PDOMFile targetFile) throws CoreException { + + public PDOMInclude(PDOMLinkage linkage, IASTPreprocessorIncludeStatement include, PDOMFile containerFile, + PDOMFile targetFile) throws CoreException { this.linkage = linkage; this.record = linkage.getDB().malloc(RECORD_SIZE); - IASTName name= include.getName(); - IASTFileLocation loc= name.getFileLocation(); - // includes generated by -include or -macro don't have a location + IASTName name = include.getName(); + char[] nameChars = name.getSimpleID(); + IASTFileLocation loc = name.getFileLocation(); + // Includes generated by -include or -macro don't have a location if (loc != null) { - setNameOffsetAndLength(loc.getNodeOffset(), (short) loc.getNodeLength()); + linkage.getDB().put3ByteUnsignedInt(record + NODE_OFFSET, loc.getNodeOffset()); + linkage.getDB().putShort(record + NODE_LENGTH, (short) loc.getNodeLength()); } - - setFlag(encodeFlags(include, targetFile == null)); + + final Database db = linkage.getDB(); + if (targetFile != null) { + db.putInt(record + INCLUDED_FILE, targetFile.getRecord()); + } + boolean deducible_name = isDeducibleName(targetFile, nameChars); + // If the name is the same as an end part of the path of the included file, + // store the length of the name instead of the name itself. + int rec= deducible_name ? nameChars.length : db.newString(nameChars).getRecord(); + db.putInt(record + INCLUDE_NAME_OR_LENGTH, rec); + setFlag(encodeFlags(include, deducible_name)); setIncludedBy(containerFile); - setIncludes(targetFile, name.getSimpleID()); } - - private byte encodeFlags(IASTPreprocessorIncludeStatement include, boolean unresolved) { + + private byte encodeFlags(IASTPreprocessorIncludeStatement include, boolean deducible_name) { byte flags= 0; if (include.isSystemInclude()) { flags |= FLAG_SYSTEM_INCLUDE; } if (!include.isActive()) { flags |= FLAG_INACTIVE_INCLUDE; - } - if (unresolved) { - flags |= FLAG_UNRESOLVED_INCLUDE; } else if (include.isResolvedByHeuristics()) { flags |= FLAG_RESOLVED_BY_HEURISTICS; } + if (deducible_name) { + flags |= FLAG_DEDUCIBLE_NAME; + } return flags; } public int getRecord() { return record; } - + public void delete() throws CoreException { if (isResolved()) { // Remove us from the includedBy chain removeThisFromIncludedByChain(); } - else { - getNameForUnresolved().delete(); + final Database db = linkage.getDB(); + if ((getFlag() & FLAG_DEDUCIBLE_NAME) == 0) { + int rec = db.getInt(record + INCLUDE_NAME_OR_LENGTH); + db.getString(rec).delete(); } - // Delete our record - linkage.getDB().free(record); + db.free(record); } private void removeThisFromIncludedByChain() throws CoreException { PDOMInclude prevInclude = getPrevInIncludedBy(); PDOMInclude nextInclude = getNextInIncludedBy(); - if (prevInclude != null) + if (prevInclude != null) { prevInclude.setNextInIncludedBy(nextInclude); - else + } else { ((PDOMFile) getIncludes()).setFirstIncludedBy(nextInclude); + } if (nextInclude != null) nextInclude.setPrevInIncludedBy(prevInclude); } - - private IString getNameForUnresolved() throws CoreException { - if (isResolved()) { - return null; - } - final Database db = linkage.getDB(); - return db.getString(db.getInt(record + INCLUDES_FILE_OR_NAME)); - } - + public IIndexFragmentFile getIncludes() throws CoreException { - if (!isResolved()) { - return null; - } - int rec = linkage.getDB().getInt(record + INCLUDES_FILE_OR_NAME); + int rec = linkage.getDB().getInt(record + INCLUDED_FILE); return rec != 0 ? new PDOMFile(linkage, rec) : null; } - - private void setIncludes(PDOMFile includes, char[] name) throws CoreException { - int rec= 0; - if (includes == null) { - rec= linkage.getDB().newString(name).getRecord(); + + /** + * Checks if the name is the same as the end part of the path of the included file. + */ + private static boolean isDeducibleName(PDOMFile includedFile, char[] name) throws CoreException { + if (includedFile == null) { + return false; } - else { - rec= includes.getRecord(); + String s = includedFile.getLocation().getURI().getPath(); + int pos = s.length() - name.length; + if (pos < 0) { + return false; } - linkage.getDB().putInt(record + INCLUDES_FILE_OR_NAME, rec); + for (int i = 0; i < name.length; i++, pos++) { + if (s.charAt(pos) != name[i]) { + return false; + } + } + return true; } - + public IIndexFile getIncludedBy() throws CoreException { int rec = linkage.getDB().getInt(record + INCLUDED_BY); return rec != 0 ? new PDOMFile(linkage, rec) : null; } - + private void setIncludedBy(PDOMFile includedBy) throws CoreException { int rec = includedBy != null ? includedBy.getRecord() : 0; linkage.getDB().putInt(record + INCLUDED_BY, rec); } - + public PDOMInclude getNextInIncludes() throws CoreException { int rec = linkage.getDB().getInt(record + INCLUDES_NEXT); return rec != 0 ? new PDOMInclude(linkage, rec) : null; } - + public void setNextInIncludes(PDOMInclude include) throws CoreException { int rec = include != null ? include.getRecord() : 0; linkage.getDB().putInt(record + INCLUDES_NEXT, rec); } - + public PDOMInclude getNextInIncludedBy() throws CoreException { int rec = linkage.getDB().getInt(record + INCLUDED_BY_NEXT); return rec != 0 ? new PDOMInclude(linkage, rec) : null; } - + public void setNextInIncludedBy(PDOMInclude include) throws CoreException { int rec = include != null ? include.getRecord() : 0; linkage.getDB().putInt(record + INCLUDED_BY_NEXT, rec); } - + public PDOMInclude getPrevInIncludedBy() throws CoreException { int rec = getPrevInIncludedByRecord(); return rec != 0 ? new PDOMInclude(linkage, rec) : null; @@ -181,7 +196,7 @@ public class PDOMInclude implements IIndexFragmentInclude { int getPrevInIncludedByRecord() throws CoreException { return linkage.getDB().getInt(record + INCLUDED_BY_PREV); } - + public void setPrevInIncludedBy(PDOMInclude include) throws CoreException { int rec = include != null ? include.getRecord() : 0; linkage.getDB().putInt(record + INCLUDED_BY_PREV, rec); @@ -192,39 +207,32 @@ public class PDOMInclude implements IIndexFragmentInclude { } public IIndexFileLocation getIncludesLocation() throws CoreException { - if (!isResolved()) { - return null; - } - return getIncludes().getLocation(); + IIndexFragmentFile includes = getIncludes(); + return includes != null ? includes.getLocation() : null; } public IIndexFragment getFragment() { return linkage.getPDOM(); } - - private void setNameOffsetAndLength(int offset, short length) throws CoreException { - linkage.getDB().putInt(record + NODE_OFFSET_OFFSET, offset); - linkage.getDB().putShort(record + NODE_LENGTH_OFFSET, length); - } - + private void setFlag(byte flag) throws CoreException { - linkage.getDB().putByte(record + FLAG_OFFSET, flag); + linkage.getDB().putByte(record + FLAGS, flag); } - + private int getFlag() throws CoreException { - return linkage.getDB().getByte(record + FLAG_OFFSET); + return linkage.getDB().getByte(record + FLAGS); } public boolean isSystemInclude() throws CoreException { return (getFlag() & FLAG_SYSTEM_INCLUDE) != 0; } - + public boolean isActive() throws CoreException { return (getFlag() & FLAG_INACTIVE_INCLUDE) == 0; } - + public boolean isResolved() throws CoreException { - return (getFlag() & FLAG_UNRESOLVED_INCLUDE) == 0; + return linkage.getDB().getInt(record + INCLUDED_FILE) != 0; } public boolean isResolvedByHeuristics() throws CoreException { @@ -232,34 +240,45 @@ public class PDOMInclude implements IIndexFragmentInclude { } public int getNameOffset() throws CoreException { - return linkage.getDB().getInt(record + NODE_OFFSET_OFFSET); + return linkage.getDB().get3ByteUnsignedInt(record + NODE_OFFSET); } - + public int getNameLength() throws CoreException { - return linkage.getDB().getShort(record + NODE_LENGTH_OFFSET) & 0xffff; + return linkage.getDB().getShort(record + NODE_LENGTH) & 0xffff; } - - public String getName() throws CoreException { + + public String getFullName() throws CoreException { if (fName == null) { - computeName(); + final Database db = linkage.getDB(); + // The include name is either stored explicitly, or can be deduced from the path + // of the included file. + if ((getFlag() & FLAG_DEDUCIBLE_NAME) == 0) { + int rec = db.getInt(record + INCLUDE_NAME_OR_LENGTH); + fName = db.getString(rec).getString(); + } else { + String path = getIncludes().getLocation().getURI().getPath(); + int nameLength = db.getInt(record + INCLUDE_NAME_OR_LENGTH); + fName = path.substring(Math.max(path.length() - nameLength, 0)); + } } return fName; } - private void computeName() throws CoreException { - if (isResolved()) { - fName= getIncludes().getLocation().getURI().getPath(); - } - else { - fName= getNameForUnresolved().getString(); - } - fName= fName.substring(fName.lastIndexOf('/')+1); + public String getName() throws CoreException { + return getFullName().substring(fName.lastIndexOf('/') + 1); } public void convertToUnresolved() throws CoreException { if (isResolved()) { - setIncludes(null, getName().toCharArray()); - setFlag((byte) (getFlag() | FLAG_UNRESOLVED_INCLUDE)); + final Database db = linkage.getDB(); + int flag = getFlag(); + // Since included file is going away, the name is no longer deducible. + if ((flag & FLAG_DEDUCIBLE_NAME) != 0) { + int rec= db.newString(getFullName()).getRecord(); + db.putInt(record + INCLUDE_NAME_OR_LENGTH, rec); + setFlag((byte) (flag & ~FLAG_DEDUCIBLE_NAME)); + } + db.putInt(record + INCLUDED_FILE, 0); } } }